SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00010 1 08-24-9413:17ALL SWAG SUPPORT TEAM High Precision BCD Math SWAG9408 ß╠æ┼ 363 ₧ unit AJCBCD;ππinterfaceππuses Objects, Strings;ππconstπ DigitSize = SizeOf(Byte);π bpw_Fixed = 0;π bpw_Variable = 1;π bpz_Blank = True;π bpz_NotBlank = False;π MaxBCDSize = 100;π st_Blanks25 = ' ';π st_Blanks = st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25π + st_Blanks25;ππtypeπ PBCDArray = ^TBCDArray;π TBCDArray = array[1..MaxBCDSize] of byte;ππ TBCDSign = (BCDNegative, BCDPositive);ππ PBCD = ^TBCD;π TBCD = object(TObject)π BCDSize: Integer;π Sign: TBCDSign;π Value: PBCDArray;π Precision: Byte;π constructor InitBCD(AVal: PBCD);π constructor InitReal(AVal: Real; APrec: Byte; ASize: Integer);π constructor InitPChar(AVal: PChar; APrec: Byte; ASize: Integer);π destructor Done; virtual;π constructor Load(var S: TStream);π procedure Store(var S: TStream);π function GetValue: PBCDArray;π function GetSign: TBCDSign;π function GetPrecision: Byte;π function GetBCDSize: Integer;π procedure SetValueBCD(AVal: PBCD);π procedure SetValueReal(AVal: Real);π procedure SetValuePChar(AVal: PChar);π procedure SetSign(ASign: TBCDSign);π procedure SetPrecision(APrec: Byte);π procedure SetBCDSize(ASize: Integer);π procedure AddBCD(AVal: PBCD);π procedure AddReal(AVal: Real);π procedure AddPChar(AVal: PChar);π procedure SubtractBCD(AVal: PBCD);π procedure SubtractReal(AVal: Real);π procedure SubtractPChar(AVal: PChar);π procedure MultiplyByBCD(AVal: PBCD);π procedure MultiplyByReal(AVal: Real; APrec: Byte);π procedure MultiplyByPChar(AVal: PChar; APrec: Byte);π procedure DivideByBCD(AVal: PBCD);π procedure DivideByReal(AVal: Real; APrec: Byte);π procedure DivideByPChar(AVal: PChar; APrec: Byte);π procedure AbsoluteValue;π procedure Increment;π procedure Decrement;π procedure ShiftLeft(ShiftAmount: Byte);π procedure ShiftRight(ShiftAmount: Byte);π function BCD2Int: LongInt;π function BCD2Real: Real;π function PicStr(picture: string;π Width: Integer; BlankWhenZero: Boolean): String;π function StrPic(dest: PChar; picture: string;π Width: Integer; BlankWhenZero: Boolean;π Size: Integer): PChar;π function CompareBCD(AVal: PBCD): Integer;π function CompareReal(AVal: Real): Integer;π function ComparePChar(AVal: PChar): Integer;π end;ππconstππ RBCD: TStreamRec = (ObjType: 60000;π VmtLink: Ofs(TypeOf(TBCD)^);π Load: @TBCD.Load;π Store: @TBCD.Store);ππvarπ BCDZero: PBCD;ππimplementationππ{BCDAdd is a subroutine that adds the value in BCD2 to the value in }π{BCD1. It is a simple magnitude addition, as if the two numbers have }π{the same sign. BCDAdd makes the following assumptions: }π{ 1) the calling routine will manage the proper sign of the result }π{ of the addition. }π{ 2) the BCDSize of the two operands are equal }π{ 3) the Precision of the two operands are equal }πprocedure BCDAdd(BCD1, BCD2: PBCD);πvarπ i: integer;π Carry: Byte;πbeginπ Carry := 0;π for i := BCD1^.BCDSize downto 1 doπ beginπ BCD1^.Value^[i] := BCD1^.Value^[i] + BCD2^.Value^[i] + Carry;π if BCD1^.Value^[i] > 9 thenπ beginπ dec(BCD1^.Value^[i], 10);π Carry := 1;π endπ elseπ Carry := 0;π end;πend;ππ{BCDSubtraction is a subroutine that subtracts the value in BCD2 from }π{the value in BCD1. It is a simple magnitude subtraction, without }π{regard to the sign of the operands. BCDSubtract makes the following }π{assumptions: }π{ 1) the calling routine will manage the proper sign of the result }π{ of the subtraction. }π{ 2) the BCDSize of the two operands are equal }π{ 3) the Precision of the two operands are equal }π{ 4) the magnitude of the value in BCD2 is less than or equal to the }π{ magnitude of the value in BCD1 so that the routine can perform }π{ a simple byte by byte subtraction }πprocedure BCDSubtract(BCD1, BCD2: PBCD);πvarπ i: integer;π Borrow: Byte;πbeginπ Borrow := 0;π for i := BCD1^.GetBCDSize downto 1 doπ beginπ BCD1^.Value^[i] := BCD1^.Value^[i] + 10 - BCD2^.Value^[i] - Borrow;π if BCD1^.Value^[i] > 9 thenπ beginπ dec(BCD1^.Value^[i], 10);π Borrow := 0;π endπ elseπ Borrow := 1;π end;πend;ππconstructor TBCD.InitBCD(AVal: PBCD);πbeginπ inherited Init;π BCDSize := AVal^.GetBCDSize;π GetMem(Value, BCDSize*DigitSize);π Precision := AVal^.GetPrecision;π SetValueBCD(AVal);πend;ππconstructor TBCD.InitReal(AVal: Real; APrec: Byte; ASize: Integer);πbeginπ inherited Init;π if ASize > MaxBCDSize thenπ BCDSize := MaxBCDSizeπ elseπ BCDSize := ASize;π GetMem(Value, ASize*DigitSize);π Precision := APrec;π SetValueReal(AVal);πend;ππconstructor TBCD.InitPChar(AVal: PChar; APrec: Byte; ASize: Integer);πbeginπ inherited Init;π if ASize > MaxBCDSize thenπ BCDSize := MaxBCDSizeπ elseπ BCDSize := ASize;π GetMem(Value, ASize*DigitSize);π Precision := APrec;π SetValuePChar(AVal);πend;ππdestructor TBCD.Done;πbeginπ FreeMem(Value, BCDSize*DigitSize);π inherited Done;πend;ππconstructor TBCD.Load(var S: TStream);πbeginπ S.Read(BCDSize, SizeOf(BCDSize));π S.Read(Sign, SizeOf(Sign));π GetMem(Value, BCDSize*DigitSize);π S.Read(Value^, BCDSize*DigitSize);π S.Read(Precision, SizeOf(Precision));πend;ππprocedure TBCD.Store(var S: TStream);πbeginπ S.Write(BCDSize, SizeOf(BCDSize));π S.Write(Sign, SizeOf(Sign));π S.Write(Value^, BCDSize*DigitSize);π S.Write(Precision, SizeOf(Precision));πend;ππfunction TBCD.GetValue: PBCDArray;πvarπ WrkValue: PBCDArray;πbeginπ GetMem(WrkValue, BCDSize*DigitSize);π Move(Value^, WrkValue^, BCDSize*DigitSize);π GetValue := WrkValue;πend;ππfunction TBCD.GetSign: TBCDSign;πbeginπ GetSign := Sign;πend;ππfunction TBCD.GetPrecision: Byte;πbeginπ GetPrecision := Precision;πend;ππfunction TBCD.GetBCDSize: Integer;πbeginπ GetBCDSize := BCDSize;πend;ππprocedure TBCD.SetValueBCD(AVal: PBCD);πvarπ SaveSize: Integer;π SavePrecision: Byte;πbeginπ if AVal = nil then exit;ππ FreeMem(Value, BCDSize*DigitSize);ππ SaveSize := GetBCDSize;π SavePrecision := GetPrecision;ππ Value := AVal^.GetValue;π BCDSize := AVal^.GetBCDSize;π Precision := AVal^.GetPrecision;ππ if Precision > SavePrecision thenπ beginπ SetBCDSize(SaveSize);π SetPrecision(SavePrecision);π endπ elseπ beginπ SetPrecision(SavePrecision);π SetBCDSize(SaveSize);π end;ππ SetSign(AVal^.GetSign);πend;ππprocedure TBCD.SetSign(ASign: TBCDSign);πvarπ i: integer;πbeginπ Sign := BCDPositive;π if ASign = BCDPositive then exit;ππ {allow negative sign only if value is non-zero}π for i := GetBCDSize downto 1 doπ if Value^[i] <> 0 thenπ beginπ Sign := BCDNegative;π exit;π end;πend;ππprocedure TBCD.SetValueReal(AVal: Real);πvarπ i, BCDIndex: integer;π ValStr: String;πbeginπ FillChar(Value^, BCDSize*DigitSize, #0);ππ Str(abs(AVal):BCDSize:Precision, ValStr);π BCDIndex := BCDSize;π for i :=length(ValStr) downto 1 doπ if ValStr[i] in ['0'..'9'] thenπ beginπ Value^[BCDIndex] := ord(ValStr[i]) - ord('0');π dec(BCDIndex);π end;ππ if AVal < 0.0 thenπ SetSign(BCDNegative)π elseπ SetSign(BCDPositive);πend;ππprocedure TBCD.SetValuePChar(AVal: PChar);πvarπ i, BCDIndex: integer;π SavePrec: Byte;π SaveSign: TBCDSign;πbeginπ if AVal = nil then exit;ππ SaveSign := BCDPositive;π SavePrec := Precision;π Precision := 0;ππ FillChar(Value^, BCDSize*DigitSize, #0);ππ if StrLen(AVal) = 0 then exit;ππ BCDIndex := BCDSize;π for i := StrLen(AVal) downto 0 doπ case AVal[i] ofπ '0'..'9': beginπ Value^[BCDIndex] := ord(AVal[i]) - ord('0');π dec(BCDIndex);π end;π '(',')','-': beginπ SaveSign := BCDNegative;π end;π '.': beginπ Precision := BCDSize - BCDIndex;π end;π end; {case}ππ SetPrecision(SavePrec);π SetSign(SaveSign);πend;ππprocedure TBCD.SetPrecision(APrec: Byte);πbeginπ if APrec = Precision then exit;π if APrec < Precision thenπ ShiftRight(Precision - APrec)π elseπ ShiftLeft(APrec - Precision);π Precision := APrec;πend;ππprocedure TBCD.SetBCDSize(ASize: Integer);πvarπ SaveSize: Integer;π WrkVal: PBCDArray;πbeginπ if ASize = GetBCDSize then exit;ππ if ASize > MaxBCDSize then ASize := MaxBCDSize;ππ GetMem(WrkVal, ASize*DigitSize);π FillChar(WrkVal^, ASize*DigitSize, #0);ππ if ASize < GetBCDSize thenπ Move(Value^[(GetBCDSize-ASize)+1], WrkVal^, ASize*DigitSize)π else if ASize > GetBCDSize thenπ Move(Value^, WrkVal^[(ASize-GetBCDSize)+1], GetBCDSize);ππ FreeMem(Value, GetBCDSize*DigitSize);π Value := WrkVal;π BCDSize := ASize;πend;ππprocedure TBCD.AddBCD(AVal: PBCD);πvarπ WrkValue: PBCD;πbeginπ WrkValue := new(PBCD, InitBCD(AVal));π WrkValue^.SetPrecision(Precision);π WrkValue^.SetBCDSize(BCDSize);π if GetSign <> AVal^.GetSign thenπ if AVal^.GetSign = BCDNegative thenπ beginπ WrkValue^.AbsoluteValue;π BCDSubtract(@Self, WrkValue);π Dispose(WrkValue, Done);π exit;π endπ elseπ {AVal^.GetSign = BCDPositive}π beginπ AbsoluteValue;π BCDSubtract(WrkValue, @Self);π SetValueBCD(WrkValue);π Dispose(WrkValue, Done);π exit;π end;ππ BCDAdd(@Self, WrkValue);π Dispose(WrkValue, Done);πend;ππprocedure TBCD.AddReal(AVal: Real);πvarπ WrkValue: PBCD;πbeginπ WrkValue := new(PBCD, InitReal(AVal, GetPrecision, GetBCDSize));π AddBCD(WrkValue);π Dispose(WrkValue, Done);πend;ππprocedure TBCD.AddPChar(AVal: PChar);πvarπ WrkValue: PBCD;πbeginπ WrkValue := new(PBCD, InitPChar(AVal, GetPrecision, GetBCDSize));π AddBCD(WrkValue);π Dispose(WrkValue, Done);πend;ππprocedure TBCD.SubtractBCD(AVal: PBCD);πvarπ WrkValue: PBCD;π SaveSign: TBCDSign;πbeginπ if AVal = nil then exit;ππ WrkValue := new(PBCD, InitBCD(AVal));π WrkValue^.SetPrecision(GetPrecision);π WrkValue^.SetBCDSize(GetBCDSize);π if GetSign <> AVal^.GetSign thenπ beginπ WrkValue^.SetSign(Sign);π BCDAdd(@Self, WrkValue);π Dispose(WrkValue, Done);π exit;π end;ππ SaveSign := Sign;π AbsoluteValue;π WrkValue^.AbsoluteValue;π if CompareBCD(WrkValue) < 0 thenπ beginπ BCDSubtract(WrkValue, @Self);π SetValueBCD(WrkValue);π if SaveSign = BCDNegative thenπ SetSign(BCDPositive)π elseπ SetSign(BCDNegative);π endπ elseπ beginπ BCDSubtract(@Self, WrkValue);π SetSign(SaveSign);π end;ππ Dispose(WrkValue, Done);πend;ππprocedure TBCD.SubtractReal(AVal: Real);πvarπ WrkValue: PBCD;πbeginπ WrkValue := new(PBCD, InitReal(AVal, GetPrecision, GetBCDSize));π SubtractBCD(WrkValue);π Dispose(WrkValue, Done);πend;ππprocedure TBCD.SubtractPChar(AVal: PChar);πvarπ WrkValue: PBCD;πbeginπ WrkValue := new(PBCD, InitPChar(AVal, GetPrecision, GetBCDSize));π SubtractBCD(WrkValue);π Dispose(WrkValue, Done);πend;ππprocedure TBCD.MultiplyByBCD(AVal: PBCD);πvarπ NewSign: TBCDSign;π WrkValue: PBCD;π HighDigit, i, j: integer;π SavePrec: Byte;πbeginπ if AVal = nil then exit;ππ if GetSign = AVal^.GetSign thenπ NewSign := BCDPositiveπ elseπ NewSign := BCDNegative;π AbsoluteValue;ππ SavePrec := Precision;π WrkValue := new(PBCD, InitReal(0, 0, GetBCDSize + AVal^.GetBCDSize));π Precision := 0;π i := 1;π while (i < AVal^.GetBCDSize) and (AVal^.Value^[i] = 0) doπ inc(i);π HighDigit := i;ππ for i := AVal^.GetBCDSize downto HighDigit doπ beginπ if AVal^.Value^[i] <> 0 thenπ for j := 1 to AVal^.Value^[i] doπ WrkValue^.AddBCD(@Self);π ShiftLeft(1);π end;ππ WrkValue^.Precision := SavePrec + AVal^.GetPrecision;π WrkValue^.SetPrecision(SavePrec);π Precision := SavePrec;π SetValueBCD(WrkValue);π SetSign(NewSign);πend;ππprocedure TBCD.MultiplyByReal(AVal: Real; APrec: Byte);πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitReal(AVal, APrec, GetBCDSize));π MultiplyByBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππprocedure TBCD.MultiplyByPChar(AVal: PChar; APrec: Byte);πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitPChar(AVal, APrec, GetBCDSize));π MultiplyByBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππprocedure TBCD.DivideByBCD(AVal: PBCD);πvarπ NewSign: TBCDSign;π WrkVal, WrkDiv, WrkQuo: PBCD;π HighDigit, i, j, IterationCount: integer;π TempPrec, QuotientPrec: Byte;πbeginπ if AVal = nil then exit;ππ if AVal^.CompareReal(0.0) = 0 then exit; {avoid zero divide}ππ if GetSign = AVal^.GetSign thenπ NewSign := BCDPositiveπ elseπ NewSign := BCDNegative;ππ WrkVal := new(PBCD, InitBCD(@Self));π WrkVal^.AbsoluteValue;ππ WrkQuo := new(PBCD, InitReal(0, 0, GetBCDSize));ππ i := 1;π while (i < WrkVal^.GetBCDSize) and (WrkVal^.Value^[i] = 0) doπ inc(i);π HighDigit := i;π WrkVal^.SetPrecision(WrkVal^.GetPrecision+(HighDigit-1));π TempPrec := WrkVal^.GetPrecision;π WrkVal^.Precision := 0;ππ WrkDiv := new(PBCD, InitBCD(AVal));π WrkDiv^.AbsoluteValue;π i := 1;π while (i < WrkDiv^.GetBCDSize) and (WrkDiv^.Value^[i] = 0) doπ inc(i);π HighDigit := i;π WrkDiv^.ShiftLeft(HighDigit - 1);π WrkDiv^.Precision := 0;ππ QuotientPrec := TempPrec - AVal^.GetPrecision;π IterationCount := WrkVal^.GetBCDSize - QuotientPrec + GetPrecision;ππ for i := 1 to IterationCount doπ beginπ while CompareBCD(WrkDiv) > 0 doπ beginπ WrkVal^.SubtractBCD(WrkDiv);π inc(WrkQuo^.Value^[WrkQuo^.GetBCDSize]);π end;π WrkDiv^.ShiftRight(1);π WrkQuo^.ShiftLeft(1);π end;ππ WrkQuo^.Precision := QuotientPrec;π SetValueBCD(WrkQuo);π SetSign(NewSign);ππ Dispose(WrkVal, Done);π Dispose(WrkQuo, Done);π Dispose(WrkDiv, Done);πend;ππprocedure TBCD.DivideByReal(AVal: Real; APrec: Byte);πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitReal(AVal, APrec, GetBCDSize));π DivideByBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππprocedure TBCD.DivideByPChar(AVal: PChar; APrec: Byte);πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitPChar(AVal, APrec, GetBCDSize));π DivideByBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππprocedure TBCD.AbsoluteValue;πbeginπ SetSign(BCDPositive);πend;ππprocedure TBCD.Increment;πbeginπ AddReal(1);πend;ππprocedure TBCD.Decrement;πbeginπ SubtractReal(1);πend;ππprocedure TBCD.ShiftLeft(ShiftAmount: Byte);πvarπ i: integer;πbeginπ if ShiftAmount = 0 then exit;π for i := 1 to (BCDSize - ShiftAmount) doπ Value^[i] := Value^[i+ShiftAmount];π for i := ((BCDSize - ShiftAmount) + 1) to BCDSize doπ Value^[i] := 0;πend;ππprocedure TBCD.ShiftRight(ShiftAmount: Byte);πvarπ i: integer;πbeginπ if ShiftAmount = 0 then exit;π for i := BCDSize downto (ShiftAmount + 1) doπ Value^[i] := Value^[i - ShiftAmount];π for i := ShiftAmount downto 1 doπ Value^[i] := 0;πend;ππfunction TBCD.BCD2Int: LongInt;πvarπ i: integer;π wrkLongInt: LongInt;πbeginπ BCD2Int := 0;π if Precision = GetBCDSize then exit;ππ wrkLongInt := 0;π i := 1;π repeatπ wrkLongInt := wrkLongInt * 10;π wrkLongInt := wrkLongInt + Value^[i];π inc(i);π until i = (GetBCDSize - GetPrecision);π if GetSign = BCDNegative thenπ BCD2Int := -wrkLongIntπ elseπ BCD2Int := wrkLongInt;πend;ππfunction TBCD.BCD2Real: Real;πvarπ i: integer;π wrkIntegerPart, wrkFractionPart: real;πbeginπ BCD2Real := 0.0;π wrkIntegerPart := 0;π wrkFractionPart := 0;ππ if GetPrecision < GetBCDSize thenπ beginπ i := 1;π repeatπ wrkIntegerPart := wrkIntegerPart * 10.0;π wrkIntegerPart := wrkIntegerPart + Value^[i];π inc(i);π until i = (GetBCDSize - GetPrecision + 1);π end;ππ if Precision > 0 thenπ beginπ i := GetBCDSize;π repeatπ wrkFractionPart := wrkFractionPart + Value^[i];π wrkFractionPart := wrkFractionPart / 10.0;π dec(i);π until i = (GetBCDSize - GetPrecision);π end;ππ if GetSign = BCDNegative thenπ BCD2Real := -(wrkIntegerPart + wrkFractionPart)π elseπ BCD2Real := (wrkIntegerPart + wrkFractionPart);πend;ππfunction TBCD.PicStr(picture: string;π Width: Integer; BlankWhenZero: Boolean): String;ππvarπ integer_str, decimal_str, pic_str, val_str: string;π decimal_encountered, significant_digits_encountered: boolean;π number_of_digits, number_of_integer_digits, number_of_decimal_digits,π sub_pic, sub_val, i: integer;ππbegin {pic}π decimal_encountered := false;π number_of_digits := 0;π number_of_integer_digits := 0;π for i := 1 to length(picture) doπ if upcase(picture[i]) in ['$', '-', '9', 'Z'] thenπ beginπ inc(number_of_digits);π if not decimal_encountered thenπ inc(number_of_integer_digits);π endπ else if picture[i] = '.' thenπ decimal_encountered := true;π number_of_decimal_digits := number_of_digits - number_of_integer_digits;ππ integer_str := '';π for i := (GetBCDSize - GetPrecision) downto 1 doπ integer_str := char(ord('0')+Value^[i]) + integer_str;π if length(integer_str) > number_of_integer_digits thenπ delete(integer_str, 1, length(integer_str)-number_of_integer_digits)π elseπ while length(integer_str) < number_of_integer_digits doπ integer_str := '0' + integer_str;ππ decimal_str := '';π for i := (GetBCDSize - GetPrecision + 1) to GetBCDSize doπ decimal_str := decimal_str + char(ord('0')+Value^[i]);π if length(decimal_str) > number_of_decimal_digits thenπ delete(decimal_str, number_of_decimal_digits+1, 255)π elseπ while length(decimal_str) < number_of_decimal_digits doπ decimal_str := decimal_str + '0';ππ val_str := integer_str + decimal_str;ππ pic_str := copy(st_Blanks, 1, length(picture));ππ significant_digits_encountered := false;π sub_pic := 1;π sub_val := 1;π while sub_pic <= length(picture) doπ beginπ if val_str[sub_val] in ['1'..'9']thenπ significant_digits_encountered := true;π if upcase(picture[sub_pic]) in ['(', ')'] thenπ if Sign = BCDNegative thenπ beginπ pic_str[sub_pic] := upcase(picture[sub_pic]);π sub_pic := sub_pic + 1;π endπ elseπ beginπ pic_str[sub_pic] := ' ';π sub_pic := sub_pic + 1;π endπ else if upcase(picture[sub_pic]) in ['Z', '$', '-'] thenπ beginπ if significant_digits_encountered thenπ pic_str[sub_pic] := val_str[sub_val]π elseπ pic_str[sub_pic] := ' ';π sub_pic := sub_pic + 1;π sub_val := sub_val + 1;π endπ else if picture[sub_pic] = '.' thenπ beginπ pic_str[sub_pic] := '.';π sub_pic := sub_pic + 1;π significant_digits_encountered := true;π endπ else if picture[sub_pic] = '9' thenπ beginπ pic_str[sub_pic] := val_str[sub_val];π if pic_str[sub_pic] = ' ' then pic_str[sub_pic] := '0';π sub_pic := sub_pic + 1;π sub_val := sub_val + 1;π significant_digits_encountered := true;π endπ else if picture[sub_pic] = ',' thenπ beginπ if pic_str[sub_pic - 1] = ' ' thenπ pic_str[sub_pic] := ' 'π elseπ pic_str[sub_pic] := ',';π sub_pic := sub_pic + 1;π endπ elseπ beginπ pic_str[sub_pic] := upcase(picture[sub_pic]);π sub_pic := sub_pic + 1;π end;π end;ππ if Sign = BCDNegative thenπ beginπ sub_pic := 0;π while (sub_pic < length(picture)) andπ (picture[sub_pic + 1] in ['(', '-', ',']) doπ sub_pic := sub_pic + 1;π while (sub_pic > 0) andπ (pic_str[sub_pic] <> ' ') doπ sub_pic := sub_pic - 1;π if (sub_pic > 0) andπ (picture[sub_pic] <> '(') thenπ pic_str[sub_pic] := '-';π end;ππ sub_pic := 0;π while (sub_pic < length(picture)) andπ (picture[sub_pic + 1] in ['(', '$', ',']) doπ sub_pic := sub_pic + 1;ππ while (sub_pic > 0) andπ (pic_str[sub_pic] <> ' ') doπ sub_pic := sub_pic - 1;ππ if (sub_pic > 0) andπ (picture[sub_pic] <> '(') thenπ pic_str[sub_pic] := '$';ππ if (BlankWhenZero) and (pic_str = BCDZero^.PicStr(picture, bpw_Fixed, false)) thenπ pic_str := copy(st_Blanks, 1, length(picture));ππ if Width = bpw_fixed thenπ PicStr := pic_strπ elseπ beginπ if pic_str[1] = ' ' thenπ beginπ sub_pic := 1;π while (sub_pic < length(pic_str)) andπ (pic_str[sub_pic] = ' ') doπ inc(sub_pic);π if pic_str[sub_pic] <> ' ' then dec(sub_pic);π delete(pic_str, 1, sub_pic);π end;π if pic_str[length(pic_str)] = ' ' thenπ beginπ sub_pic := length(pic_str);π while (sub_pic > 1) andπ (pic_str[sub_pic] = ' ') doπ dec(sub_pic);π if pic_str[sub_pic] <> ' ' then inc(sub_pic);π delete(pic_str, sub_pic, 255);π end;π PicStr := pic_str;π end;πend;ππfunction TBCD.StrPic(dest: PChar; picture: string;π Width: Integer; BlankWhenZero: Boolean;π Size: Integer): PChar;πvarπ WrkStr: array[0..300] of char;πbeginπ if dest = nil thenπ beginπ StrPic := nil;π exit;π end;ππ StrPCopy(WrkStr, PicStr(picture, Width, BlankWhenZero));π StrLCopy(dest, WrkStr, Size);π StrPic := dest;πend;ππfunction TBCD.CompareBCD(AVal: PBCD): Integer;πvarπ i: integer;π BCD1, BCD2: PBCD;πbeginπ if AVal = nil then exit;ππ if GetSign < AVal^.GetSign thenπ beginπ CompareBCD := -1;π exit;π endπ else if GetSign > AVal^.GetSign thenπ beginπ CompareBCD := +1;π exit;π end;ππ BCD1 := new(PBCD, InitBCD(@Self));π BCD2 := new(PBCD, InitBCD(AVal));π if GetBCDSize > AVal^.GetBCDSize thenπ BCD2^.SetBCDSize(GetBCDSize)π elseπ BCD1^.SetBCDSize(AVal^.GetBCDSize);ππ CompareBCD := 0;π for i := 1 to BCD1^.GetBCDSize doπ beginπ if BCD1^.Value^[i] < BCD2^.Value^[i] thenπ beginπ if BCD1^.GetSign = BCDNegative thenπ CompareBCD := +1π elseπ CompareBCD := -1;π Dispose(BCD1, Done);π Dispose(BCD2, Done);π exit;π endπ else if BCD1^.Value^[i] > BCD2^.Value^[i] thenπ beginπ if BCD1^.GetSign = BCDNegative thenπ CompareBCD := -1π elseπ CompareBCD := +1;π Dispose(BCD1, Done);π Dispose(BCD2, Done);π exit;π end;π end;πend;ππfunction TBCD.CompareReal(AVal: Real): Integer;πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitReal(AVal, GetPrecision, GetBCDSize));π CompareReal := CompareBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππfunction TBCD.ComparePChar(AVal: PChar): Integer;πvarπ WrkVal: PBCD;πbeginπ WrkVal := new(PBCD, InitPChar(AVal, GetPrecision, GetBCDSize));π ComparePChar := CompareBCD(WrkVal);π Dispose(WrkVal, Done);πend;ππbeginπ BCDZero := new(PBCD, InitReal(0.0, 2, 3));π RegisterType(RBCD);πend.ππ{ DOCUMENTATION }ππAJCBCD - Binary Coded Decimal (BCD) UnitπππThis unit was written using Borland International's Borland Pascal v7.0, andπthe Object Windows Library (OWL)/Turbo Vision (TV) library objects providedπwith that product.ππππI have not copyrighted this program, and donate it to the public domain. Allπportions of this program may be used, modified, and/or distributed, in wholeπor in part.πππI wrote this unit to provide myself with some reusible functions that wouldπprovide support for BCD math similar to what I've grown accustomed to withπthe COBOL Packed Decimal (COMP-3) data type. Note that in true "PackedπDecimal", two decimal digits are "packed" into each data byte. I chose notπto implement my BCD support in that manner. I may be less efficient in termsπof space, but I simply placed a single decimal digit in each byte.ππI am just a "hobby" programmer, having written nothing for anyone byt myself.πTherefore, this unit may not be "elegant"; and, there are certainly betterπways of implementing some of the routines that I coded (like perhaps codingπsome in assembler which I'm NOT very good at). However, it has met my ownπneeds, and I'm actually a little proud of what I accomplished hereπ(especially in being able to figure out algorithms to multiply and divide!).πBy the way, let me admit one thing right up front...I have NOT tested ALL ofπthe routines in this unit (in particular, the Divide routine). I clearlyπmarked all of the routines that have not been fully tested. You can assumeπthat all other routines HAVE been tested, because I used them in a realπapplication.ππThis might not be the best BCD routines available, but they might actually beπusefull to someone else--besides, it's free! I am open to suggestions,πcomments, or enhancements (although, I can't promise quick turn around becauseπI have a real job, plus I teach, plus I have a family--then I code for funπ--in that order <grin>). My CompuServe ID is 71331,501.ππThis unit exports some constants (described below). But, the big deal inπthis unit is the Binary Coded Decimal object that this unit defines. Thisπobject (TBCD) allows you to allocate a BCD data type of any number of digits.πThis object then provides methods for adding, subtracting, multiplying,πand dividing to/from/by other numbers. It also has methods for alteringπthe number of digits stored as well as the precision (number of places afterπthe decimal place).πππConstantsπ---------πDigitSize - Stores the size, in bytes, of each individual digit (currentlyπ one byte).ππbpw_Fixed - Passed to the PicSTR and STRPic methods (see the description ofπ PicSTR for an explanation of how to use this constant).ππbpw_Variable - See bpw_Fixed above.ππbpz_Blank - See bpw_Fixed above.ππbpz_NotBlank - See bpw_Fixed above.ππMaxBCDSize - Limits the maximum number of BCD digits that can be allocatedπ for a BCD object. Arbitrarily set to 100.ππst_Blanks25 - A string constant containing 25 blanks. Used just as aπ convenience in building the st_Blanks constant (see below).ππst_Blanks - A String constant containing 255 blanks. Used simply as aπ convenient reference/resource for lots of blanks (sort of likeπ the "SPACES" constant in COBOL).ππRBCD - TStreamRec used for registering the TBCD object type for use withπ streams.πππVarπ---πBCDZero - A PBCD object that is initialized to a value of zero in the unit'sπ initialization section. Used as a convenience whenever you needπ a BCD object with a value of zero.πππTypeπ----πTBCDArray - An array of "MaxBCDSize" (100) bytes. Allocated by the TBCDπ object to store the BCD value. Each byte stores an individualπ digit of the value.ππTBCDSign - An enumerated data type used by the TBCD object to represent theπ sign of the BCD value. Valid values are "BCDNegative" andπ "BCDPositive".πππππTBCDπ-----------------------------------------------------------------------------π TObject TBCDπ┌──────┐ ┌─────────────────────────────────┐π│ │ │ BCDSize │π├──────┤ │ Sign │π│ Init │ │ Value │π│*Done │ │ Precision │π│ Free │ ├─────────────────────────────────┤π└──────┘ │ InitBCD MultiplyByBCD │π │ InitReal MultiplyByReal │π │ InitPChar MultiplyByPChar │π │ Done DivideByBCD │π │ Load DivideByReal │π │ Store DivideByPChar │π │ GetValue AbsoluteValue │π │ GetSign Increment │π │ GetPrecision Decrement │π │ GetBCDSize ShiftLeft │π │ SetValueBCD ShiftRight │π │ SetValueReal BCD2Int │π │ SetValuePChar BCD2Real │π │ SetSign PicStr │π │ SetPrecision StrPic │π │ SetBCDSize CompareBCD │π │ AddBCD CompareReal │π │ AddReal ComparePChar │π │ AddPChar │π │ SubtractBCD │π │ SubtractReal │π │ SubtractPChar │π └─────────────────────────────────┘ππFields ---------------------------------------------------------------------ππBCDSize: Integer; Read OnlyππThe size, in number of digits, of the BCD number. Count represents theπavailable space for digits, and does NOT include the decimal point, or sign.πππSign: TBCDSign; Read OnlyππThe mathmatical sign of the current value (i.e., indicates whether theπcurrent value is positive or negative).πππValue: PBCDArray; Read OnlyππA pointer to a TBCDArray (an array of bytes) used to store the value of theπBCD number. Even though TBCDArray is defined with "MaxBCDSize" entries, onlyπBCDSize bytes are actually allocated from memory. Therefore, you must beπsure to be careful never to read or write to subscript values greater thanπBCDSize. If you need to change the number of digits allocated you should useπthe SetBCDSize method. The BCD value is stored in the array with the lowestπorder digit in the BCDSize position and the highest order digit in the 1stπposition. For example, if BCDSize is 5, Precision is 2, and the value beingπstored is 2.35, then a 5-byte array would be allocated on the heap, and theπarray values would be (in order from position 1 to 5) (0, 0, 2, 3, 5).πππPrecision: Byte; Read OnlyππThis value represents the number of digits after the decimal point. Keep inπmind that there is no actual decimal point stored.πππMethods ---------------------------------------------------------------------ππInitBCDππconstructor InitBCD(AVal: PBCD);ππSets BCDSize, Sign, and Precision to the same values as the BCD objectπreferred to by AVal. It then calls SetValueBCD passing AVal in order toπallocate a TBCDArray for Value, and copies the AVal^.Value into this object'sπValue array.πππInitRealππconstructor InitReal(AVal: Real; APrec: byte; ASize: Integer);ππSets BCDSize to ASize, Precision to APrec, then calls SetValueReal(AVal) inπorder to allocate a Value array and initialize it with the value in AVal.πππInitPChar ** Not yet tested **ππconstructor InitPChar(AVal: PChar; APrec: byte; ASize: Integer);ππSets BCDSize to ASize, Precision to APrec, then calls SetValuePChar(AVal)πin order to allocate a Value array and initialize it with the value in AVal.πππDoneππdestructor Done; virtual;ππFrees the memory allocated for the Value array and calls "inherited Done".πππLoadππconstructor Load(var S: TStream);ππconstructs and loads a BCD object from the stream S by first loading BCDSize,πSign, the Value array, and last the Precision.πππStoreππprocedure Store(var S: TStream);ππStores the BCD object on the stream S by storing the BCDSize, Sign, Valueπarray, and the Precision.πππGetValueππfunction GetValue: PBCDArray;ππAllocates a new TBCDArray of size BCDSize and copies the value in Value intoπthe new array, then returns a pointer to the new array. Note that it willπbe the calling routine's responsibility for disposing the array pointed to byπthe returned pointer (use GetBCDSize to determine how much memory to free).πFreeMem should be used for this disposal, not Dispose.πππGetSignππfunction GetSign: TBCDSign;ππReturns the sign of the BCD value. The sign is returned as a TBCDSignπvalue; either "BCDNegative", or "BCDPositive".πππGetPrecisionππfunction GetPrecision: Byte;ππReturns a byte value equal to the Precision (number of decimal places) of theπBCD number.πππGetBCDSizeππfunction GetBCDSize: Inteteger;ππReturns an integer value representing the number of BCD digits allocated inπthe Value array.πππSetValueBCDππprocedure SetValueBCD(AVal: PBCD);ππIf Value is not nil, then the current Value array is freed. Next, a new arrayπof size BCDSize is allocated on the heap, by calling AVal^.GetValue. Next,πthe copied value array is adjusted from the size and precision of AVal toπthe BCDSize and Precision of this BCD object (if different). Lastly, theπsign of the value is copied by calling AVal^.GetSign.πππSetValueRealππprocedure SetValueReal(AVal: Real);ππThe current value array is initialized to all zero digits. AVal is convertedπto a string, and that string is copied digit by digit into the array. IfπAVal is less than zero then Sign is set to BCDNegative, otherwise it is setπto BCDPositive.πππSetValuePChar ** Not Tested Yet **ππprocedcure SetValuePChar(AVal: PChar);ππThe current value array is initialized to all zero digits. AVal is copiedπinto the array digit by digit. This routine validity checking to verify thatπthe string actually represents a numeric value. The only character valuesπthat are processed are: 1) numbers (0-9), 2) period (locates decimal point),πand 3) minus sign or parentheses to determine that the sign is negative.πExamples: "(123.45)" would be interpreted as negative 123.45; "123.45" wouldπbe interpreted as positive 123.45; "-123.45" would be interpreted as negativeπ123.45. Likewise, "555-55-5555" would be interpreted as a negativeπ555555555; and "I'll have 2" would be interpreted as a positive 2. If thereπare no number characters in the string at all, then the resulting value isπzero.πππSetSignππprocedure SetSign(ASign: TBCDSign);ππSets Sign to ASign (either BCDNegative or BCDPositive). Regardless of theπvalue of ASign, if the Value of the BCD is zero, then SetSign forces Sign toπbe BCDPositive (in otherwords, BCD never stores a negative zero).πππSetPrecisionππprocedure SetPrecision(APrec: Byte);ππSets Precision to APrec. It also shifts the value array left or right,πdepending on whether the precision is being increased or decreased. If theπdecimals are shifted left, dropping high order digits (hopefully zeros), andπpadding zeros on the right. If the precision is being decreased, the digitsπare shifted to the right, padding the high order digits with zeros, andπdropping low order digits. Note that the size of the value array is NOTπchanged by this method.πππSetBCDSizeππprocedure SetBCDSize(ASize: Integer);ππSets BCDSize to ASize. It also allocates a new value array of the new size,πand copies value from the original value array to the new one. The valueπis copied right justified (in otherwords, high order digits are droppedπor padded with zeros depending on whether the new size is larger or smallerπthan the old size). The original value array is freed, and Value is set toπpoint to the new value array.πππAddBCDππprocedure AddBCD(AVal: PBCD);ππAdds AVal^.Value to Self.Value. This is a "signed add". By that I mean that theπsigns of the two operands ARE taken into account when adding the two valuesπtogether. The result is stored in the Value array. Mathmatically, it mightπbe represented by the following formula: "Self := Self + AVal;"πππAddRealππprocedure AddReal(AVal: Real);ππConverts AVal to a temporary PBCD object and calls AddBCD to add thatπtemporary BCD number to Self.πππAddPChar ** Not yet tested **ππprocedure AddPChar(AVal: PChar);ππConverts AVal to a temporary PBCD object and calls AddBCD to add thatπtemporary BCD number to Self.πππSubtractBCDππprocedure SubtractBCD(AVal: PBCD);ππSubtracts AVal^.Value from Self.Value. This is a "signed subtract". By thatπI mean that the signs of the two operands ARE taken into account whenπsubtracting the two values. The result is stored in the Value array.πMathmatically, it might be represented by the following formula:π"Self := Self - AVal;"πππSubtractReal ** Not yet tested **ππprocedure SubtractReal(AVal: Real);ππConverts AVal to a temporary PBCD object and calls SubtractBCD to subtractπthat temporary BCD number from Self.πππSubtractPChar ** Not yet tested **ππprocedure SubtractPChar(AVal: PChar);ππConverts AVal to a temporary PBCD object and calls SubtractBCD to subtractπthat temporary BCD number from Self.πππMultiplyByBCDππprocedure MultiplyByBCD(AVal: PBCD);ππMultiplies Self.Value by AVal^.Value. This is a "signed multiply". By thatπI mean that the signs of the two operands ARE taken into account whenπmultiplying the two values. The result is stored in the Value array.πMathmatically, it might be represented by the following formula:π"Self := Self * AVal;"πππMultiplyByReal ** Not yet tested **ππprocedure MultiplyByReal(AVal: Real);ππConverts AVal to a temporary PBCD object and calls MultiplyByBCD toπmultiply Self by that temporary BCD number.πππMultiplyByPChar ** Not yet tested **ππprocedure MultiplyByPChar(AVal: PChar);ππConverts AVal to a temporary PBCD object and calls MultiplyByBCD toπmulitiply Self by that temporary BCD number.πππDivideByBCD ** Not yet tested **ππprocedure DivideByBCD(AVal: PBCD);ππDivides Self.Value by AVal^.Value. This is a "signed divide". By thatπI mean that the signs of the two operands ARE taken into account whenπdividing the two values. The result is stored in the Value array.πMathmatically, it might be represented by the following formula:π"Self := Self/AVal;"πππDivideByReal ** Not yet tested **ππprocedure DivideByReal(AVal: Real);ππConverts AVal to a temporary PBCD object and calls DivideByBCD to divideπSelf by that temporary BCD number.πππDivideByPChar ** Not yet tested **ππprocedure DivideByPChar(AVal: Real);ππConverts AVal to a temporary PBCD object and calls DivideByBCD to divideπSelf by that temporary BCD number.πππAbsoluteValueππprocedure AbsoluteValue;ππCalls SetSign to set Sign to BCDPositive, regardless of its current value.πππIncrement ** Not yet tested **ππprocedure Increment;ππAdds 1 Value.πππDecrement ** Not yet tested **ππprocedure Decrement;ππSubtracts 1 from Value.πππShiftLeftππprocedure ShiftLeft(ShiftAmount: Byte);ππShifts all of the digits left by ShiftAmount, dropping high order digits, andπpadding the low order digits with zeros. The Precision of the number is NOTπaltered. In effect, ShiftLeft multiplies Value by a power of 10.πππShiftRightππprocedure ShiftRight(ShiftAmount: Byte);ππShifts all of the digits right by ShiftAmount, dropping low order digits, andπpadding the high order digits with zeros. The Precision of the number is NOTπaltered. In effect, ShiftRight divides Value by a power of 10.πππBCD2Int ** Not yet tested **ππfunction BCD2Int: LongInt;ππConverts the BCD value (and it's sign) to a LongInt data value. Decimalπpositions are simply truncated, not rounded. Range checking is not performed.πIf the number of significant digits of the BCD number (not counting decimalπpositions) is too large for a LongInt number, high order digits are lost,πand the resulting LongInt value will probably be meaningless.πππBCD2Real ** Not yet tested **ππfunction BCD2Real: Real;ππConverts the BCD value (and it's sign) to a Real data value. Range checkingπis not performed. If the number of significant digits of the BCD number isπtoo loarge for a Real number, the results are unpredictable, and willπprobably be meaningless.πππPicStrππfunction PicStr(picture: string;π Width: Integer; BlankWhenZero: Boolean): string;ππPicStr converts the BCD number into a formatted Pascal string. If you areπfamiliar with the used of Edit Numeric Formatting in Cobol, then you're aπlong ways toward understanding how to use this routine.ππFirst, let's get the simple parameters out of the way...ππWidth indicates whether or not insignificant leading and trailing blanksπshould be removed from the resulting string. If Width is equal to 0 then theπlength of the resulting string will always equal the length of Picture,πregardless of any leading or trailing blanks in the result string. If Widthπis equal to 1, then any leading and/or trailing blanks will be removed fromπthe resulting string before returning. For your convenience, two constantsπhave been defined for use with this parameter: bpw_Fixed = 0 andπbpw_Variable = 1.ππBlankWhenZero indicates whether the entire result string should be forced toπcompletely blank, regardless of any formatting characters in Picture, if theπformatted value is logically equal to zero. The BCD value itself is NOT usedπto make this determination. The determination is made by comparing theπresult string to the string from formatting BCDZero (zero value) with theπsame Picture string. If the two strings are equal, then this result stringπis considered to be equal to zero. If BlankWhenZero is true, then such zeroπvalued results are forced to all blanks. If BlankWhenZero is false, theπthe result string is left to whatever it becomes based on the Picture string.πIf BlankWhenZero is true, and Width = bpw_Fixed, then the result string isπa string of blanks equal in length to the length of Picture. If Width =πbpw_Variable, the the result will be an empty strint (''). For example, ifπthe BCD number = 0.0023, and the formatted result is "0.00%", BlankWhenZero =πfalse would result in "0.00%", while BlankWhenZero = true would result in aπblank or empty string depending on Width. For your convenience, two constantsπhave been defined for use with this parameter: bpz_Blank = true, andπbpz_NotBlank = false.ππNow, the more complicated part...picture...ππThe "picture" parameter is a string that provides a template for formattingπthe value of the BCDnumber. The possible template characters are...π '9' - Fills with a digit from the value (or zero if no digit positionπ available in the BCD number)π 'Z' - Just like '9', except that insignificant zeros (i.e., leading zeros)π are left blank.π 'z' - Exactly the same as a capital "Z"π '$' - Just like 'Z', except that the right most unused (blank)π dollar-sign position is filled with a '$'. COBOL afficianados willπ recognize this as a "floating dollar sign".π '-' - Just like 'Z', except that if the BCD number value is negative, thenπ the right most unused (blank) dash position is filled with a '-'.π COBOL afficianoados will recognize this as a "floating negative sign".π '(' - If the template contains a parenthesis, and the BCD number value isπ negative, then the result string is surrounded with parenthesis.π ')' - If the template contains a parenthesis, and the BCD number value isπ negative, then the result string is surrounded with parenthesis.π '.' - Indicates the decimal point position, and is included in the resultπ string. If the template does not contain a period, then the decimalπ position is assumed to be at the right end of the template, noπ decimal point is included in the result string, and no decimal placeπ values are included in the result string.π ',' - If any significant (non-zero) value positions precede the commaπ position, then a comma is inserted at this position in the resultπ string. This would normally be used to format commas to separateπ thousands positions in large numbers.π ANY other characters are simply inserted into the result string in theirπ relative position.ππSome examples might help...ππ Value Picture String Fixed Result Variable Resultπ 123.45 '$$$$$9.99' ' $123.45' '$123.45'π 123456.78 '$$$$$9.99' '123456.78' '123456.78'π 123456.78 '$$$$$$9.99' '$123456.78' '$123456.78'π 123456.78 '$,$$$,$$9.99' '$123,456.78' '$123,456.78'π 123.45 '9999' '0123' '0123'π -1234.6 '---,--9.99' ' -1,234.60' '-1,234.60'π -10.15 '(99.99)' '(10.15)' '(10.15)'π 10.15 '(99.99)' ' 10.15 ' '10.15'π 75 'z9.999%' '75.000%' '75.000%'ππGot the idea? I hope so. I have developed a similar stand-alone routineπfor formatting inteter and real numbers, and find it to be a VERY handy wayπto nicely format my number values for presentation on the screen or on aπpaper report.πππStrPic ** Not yet tested **ππfunction StrPic(dest: PChar; picture: string;π Width: Integer; BlankWhenZero: Boolean): PChar;ππCalls PicStr(picture, Width, BlankWhenZero) to get a formatted Pascal string.πThis string is converted to an null terminated string. StrLCopy is used toπcopy that null terminated string to Dest, limited by Size. See PicStr for anπexplanation of the use of picture, Width, and BlankWhenZero. StrPic returnsπa pointer to dest.πππCompareBCDππfunction CompareBCD(AVal: PBCD): Integer;ππCompares the signed values of Self and AVal. CompareBCD returns -1 if Selfπis less than AVal, returns +1 of Self is greater than AVal, and returns 0 ifπthe two values are equal.πππCompareReal ** Not yet tested **ππfunction CompareReal(AVal: Real): Integer;ππConverts AVal to a temporary PBCD object and calls CompareBCD to perform theπactual comparison with that temporary BCD number. CompareReal returns theπvalue returned by CompareBCD.ππComparePChar ** Not yet tested **πππfunction ComparePChar(AVal: PChar): Integer;ππConverts AVal to a temporary PBCD object and calls CompareBCD to perform theπactual comparison with that temporary BCD number. ComparePChar returns theπvalue returned by CompareBCD. 2 08-24-9413:24ALL EUGENE VENTIMIGLIA Type Really Big Number SWAG9408 =á· 25 ₧ {π I wrote routines to add and multiply any amount of bytes one at a time,π but then had no way to test them out:)π}πprogram Really_Big_Math;ππtype ReallyBigNumber = array[0..100] of byte;π {Byte [0] is the length, [1] is least significant}ππprocedure ShiftRBN(var A:ReallyBigNumber;N:byte);πvar Index:Byte;πbeginπ if n<>0 then beginπ for Index :=(A[0] + N) downto N+1 do A[Index] := A[Index - N];π for Index := 1 to N do A[Index] := 0;π Inc(A[0],N);π end;πend;ππprocedure ByteAdd(A,B:Byte; var C,S:byte);πvar temp:word;πbeginπ temp := A+B+C;π C := temp div 256;π S := temp mod 256;πend;ππProcedure ByteMult(A,B:Byte;var C,P:byte);πvar temp:word;πbeginπ temp:=A*B+C;π C:=temp div 256;π P:=temp mod 256;πend;πππProcedure Sum(N1,N2:ReallyBigNumber;var S:ReallyBigNumber);πvar WorkArray : ReallyBigNumber;π L,Index,π Carry : byte;ππbeginπ Carry := 0;WorkArray[0] := 0;π if N1[0] = 0 then for Index := 1 to 100 do N1[Index] := 0;π if N2[0] = 0 then for Index := 1 to 100 do N2[Index] := 0;π if N1[0] > N2[0] then L := N1[0] else L := N2[0];π for Index := 1 to L do beginπ ByteAdd(N1[Index],N2[Index],Carry,WorkArray[Index]);π inc(WorkArray[0]);π end;π if Carry <> 0 then inc(WorkArray[0]);π WorkArray[L+1]:= Carry;π S := WorkArray;πend;ππprocedure Product(N1,N2:ReallyBigNumber;var PR:ReallyBigNumber);πvar C1,C2,L1,L2,π Carry :Byte;π TProduct,π WorkRBN :ReallyBigNumber;πbeginπ WorkRBN[0] := 0;π L1 := N1[0];L2 := N2[0];π for C1 := 1 to L1 do beginπ Carry:=0;TProduct[0]:=0;π for C2 := 1 to L2 do beginπ ByteMult(N1[C1],N2[C2],Carry,TProduct[C2]);π inc(TProduct[0]);π end;π if Carry<>0 then beginπ TProduct[C2+1] := Carry;π inc(TProduct[0]);π end;π ShiftRBN(TProduct,C1-1);π Sum(TProduct,WorkRBN,WorkRBN)π end;π PR := WorkRBN;πend;ππprocedure STR2RBN(S:String; var R:ReallyBigNumber);ππvar Index,π SLen : Byte;π Value,π RBNTen,π RBNPlus : ReallyBigNumber;ππ function Ch2Val(C:Char):Byte;π beginπ Ch2Val := ord(C) - 48;π end;ππbeginπ SLen := Length(S);π RBNTen[0] := 1; RBNTen[1] := 10; {To Multiply Value by Ten}π RBNPlus[0] := 1; RBNPlus[1] := 0; {To add to Value}π Value[0] := 1; Value[1] := Ch2Val(S[1]);π if SLen > 1 thenπ for Index := 2 to SLen do begin (***THANKS DJ!!***)π RBNPlus[1] := Ch2Val(S[Index]);π Product(RBNTen,Value,Value);π Sum(RBNPlus,Value,Value);π end;π R := Value;πend;ππprocedure RBN2Real(RBN:ReallyBigNumber;var RR:Real);πvar RValue:Real;πbeginπ RValue:=0;π repeatπ RValue := RValue * 256;π RValue := RValue + RBN[RBN[0]];π dec(RBN[0]);π until RBN[0] < 1;π RR := RValue;πend;ππvar AA,BB,SS,PP: ReallyBigNumber;π StA,StB : String;π RealP,RealS : Real;ππbeginπ Writeln('Input A');π Readln(StA);π Writeln('Input B');π Readln(StB);π STR2RBN(StA,AA);π STR2RBN(StB,BB);π Sum(AA,BB,SS);π Product(AA,BB,PP);π RBN2Real(SS,RealS);π RBN2Real(PP,RealP);π Writeln('Sum =',RealS);π Writeln('Product =',RealP);πend.π 3 08-24-9413:51ALL DAVE NEMETH Prime Numbers SWAG9408 ╒,░] 8 ₧ {πI'm studying pascal on my own and was given an assignment to determine if aπpositive number is prime. This was in a chapter where functions wereπdiscussed. I've struggled with this problem for a week and have given up. Theπfollowing code is the best I can come up with. It is not correct. Wouldπsomeone please evaluate this and tell me what is wrong with it?π}ππPROGRAM PrimeNumbers;π{ Exercise to determine if a positive number is a prime }πVAR x : WORD;π πFUNCTION prime (p : WORD) : BOOLEAN;πBEGIN { Prime }π prime := (p MOD 2 <> 0) AND (p MOD 3 <> 0) AND (p MOD 5 <> 0)πEND; { Prime }ππBEGIN { Main }π REPEATπ WRITE ('Enter a positive number. 0 to quit: ');π READLN (x);π IF prime (x) THENπ WRITELN (x, ' is a prime number')π ELSEπ WRITELN (x, ' is NOT prime');π UNTILπ x = 0π END. { Main }π 4 08-24-9417:50ALL WIM VAN DER VEGT Text Formula Parser SWAG9408 δy' 349 ₧ {---------------------------------------------------------}π{ Project : Text Formula Parser }π{ Auteur : G.W. van der Vegt }π{---------------------------------------------------------}π{ Datum .tijd Revisie }π{ 900530.1900 Creatie (function call/exits removed). }π{ 900531.1900 Revisie (Boolean expressions). }π{ 900104.2100 Revisie (HEAP Function Storage). }π{ 910327.1345 External Real string vars (tfp_realstr) }π{ are corrected the same way as the parser }π{ corrects them before using TURBO's VAL. }π{ 910829.1200 Support added for recursion with string }π{ variables so they may contain formula's }π{ now. }π{ 940411.1300 Hyperbolic, reciproke & inverse }π{ goniometric functions added, }π{ Type of tfp_lnr changed to Byte. }π{ Bug fixed in tfp_check (tfp_lnr not always}π{ initialized to 0) }π{---------------------------------------------------------}ππUNIT Tfp_02;ππINTERFACEππCONSTπ tfp_true = 1.0; {----REAL value for BOOLEAN TRUE }π tfp_false = 0.0; {----REAL value for BOOLEAN FALSE }π tfp_maxparm = 16; {----Maximum number of parameters }π tfp_funclen = 12; {----Maximum function name length }ππTYPEπ tfp_fname = STRING[tfp_funclen]; {----Function Name or Alias }π tfp_ftype = (tfp_noparm, {----Function or Function() }π tfp_1real, {----Function(VAR r) }π tfp_2real, {----Function(VAR r1,r2) }π tfp_nreal, {----Function(VAR r;n INTEGER) }π tfp_realvar, {----Real VAR }π tfp_intvar, {----Integer VAR }π tfp_boolvar, {----Boolean VAR }π tfp_strvar); {----String VAR (Formula) }ππ tfp_rarray = ARRAY[0..tfp_maxparm-1] OF REAL;ππFUNCTION Tfp_parse2real(s : STRING): REAL;ππFUNCTION Tfp_parse2str(s : STRING;m,n : INTEGER) : STRING;ππ{---------------------------------------------------------}π{----Interface to error functions for external addons }π{---------------------------------------------------------}ππVARπ tfp_erpos,π tfp_ernr : BYTE;ππPROCEDURE Tfp_seternr(ernr : INTEGER);ππFUNCTION Tfp_errormsg(nr : INTEGER) : STRING;ππ{---------------------------------------------------------}π{----Initialize & Expand internal parser datastructure }π{---------------------------------------------------------}ππPROCEDURE Tfp_init (no : WORD);ππPROCEDURE Tfp_expand(no : WORD);ππ{---------------------------------------------------------}π{----Keep first no function+vars of parser }π{---------------------------------------------------------}ππPROCEDURE Tfp_keep (no : WORD);ππ{---------------------------------------------------------}π{----Number of functions+vars added to parser }π{---------------------------------------------------------}ππFUNCTION Tfp_noobj : WORD;ππ{---------------------------------------------------------}π{----Adds own FUNCTION or VAR to the parser }π{ All FUNCTIONS & VARS must be compiled }π{ with the FAR switch on }π{---------------------------------------------------------}ππPROCEDURE Tfp_addobj(adres : POINTER;π name : tfp_fname;π ftype : tfp_ftype);ππ{---------------------------------------------------------}π{----Add Internal Function Packs }π{---------------------------------------------------------}ππPROCEDURE Tfp_addgonio;πPROCEDURE Tfp_addlogic;πPROCEDURE Tfp_addmath;πPROCEDURE Tfp_addmisc;πPROCEDURE Tfp_addall;ππ{---------------------------------------------------------}ππIMPLEMENTATIONππTYPEπ tfp_parse_state = RECORDπ tfp_line : STRING; {----Copy of string to Parse }π tfp_lp : BYTE; {----Parsing Pointer into Line }π tfp_nextchar : CHAR; {----Character at Lp Postion }π END;ππ tfp_state_ptr = ^tfp_parse_state;ππCONSTπ tfp_maxreal = +9.99999999e37; {----Internal maxreal }π tfp_maxlongint = maxlongint-1; {----Internal longint }ππVARπ maxfie : INTEGER; {----max no of functions & vars }π fiesiz : INTEGER; {----current no of functions & vars }π p : tfp_state_ptr; {----Top level formula }ππTYPEπ tfp_fie_typ = RECORDπ tfp_fname : tfp_fname;{----Name of function or var }π tfp_faddr : POINTER; {----FAR POINTER to function or var}π tfp_ftype : tfp_ftype;{----Type of entry }π END;ππ tfp_fieptr = ARRAY[1..1] OF tfp_fie_typ; {----Open Array Construction }ππVARπ fiearr : ^tfp_fieptr; {----Array of functions & vars }ππ{---------------------------------------------------------}π{----Tricky stuff to call FUNCTIONS }π{ Idea from Borland's DataBase ToolKit }π{---------------------------------------------------------}ππ{$F+}ππVARπ glueptr : POINTER;ππFUNCTION Tfp_call_noparm : REAL;ππ INLINE($ff/$1e/glueptr); {CALL DWORD PTR GluePtr}ππFUNCTION Tfp_call_1real(VAR lu_r) : REAL;ππ INLINE($ff/$1e/glueptr); {CALL DWORD PTR GluePtr}ππFUNCTION Tfp_call_2real(VAR lu_r1,lu_r2) : REAL;ππ INLINE($ff/$1e/glueptr); {CALL DWORD PTR GluePtr}ππFUNCTION Tfp_call_nreal(VAR lu_r,lu_n) : REAL;ππ INLINE($ff/$1e/glueptr); {CALL DWORD PTR GluePtr}ππ{$F-}ππ{---------------------------------------------------------}π{----TP round function not useable }π{---------------------------------------------------------}ππFUNCTION Tfp_round(VAR r : REAL) : LONGINT;ππBEGINπ IF (r<0)π THEN Tfp_round:= Trunc(r - 0.5)π ELSE Tfp_round:= Trunc(r + 0.5);πEND; {of Tfp_round}ππ{---------------------------------------------------------}π{----This routine set the tfp_ernr if not set already }π{---------------------------------------------------------}ππPROCEDURE Tfp_seternr(ernr : INTEGER);ππBEGINπ IF (tfp_ernr=0)π THENπ BEGINπ tfp_erpos:=p^.tfp_lp;π tfp_ernr :=ernr;π END;πEND; {of Tfp_Seternr}ππ{---------------------------------------------------------}π{----This routine skips one character }π{---------------------------------------------------------}ππPROCEDURE Tfp_newchar(p : tfp_state_ptr);ππBEGINπ WITH p^ DOπ BEGINπ IF (tfp_lp<Length(tfp_line))π THEN Inc(tfp_lp);π tfp_nextchar:=Upcase(tfp_line[tfp_lp]);π END;πEND; {of Tfp_Newchar}ππ{---------------------------------------------------------}π{----This routine skips one character and }π{ all folowing spaces from an expression }π{---------------------------------------------------------}ππPROCEDURE Tfp_skip(p : tfp_state_ptr);ππBEGINπ WITH p^ DOπ REPEATπ Tfp_newchar(p);π UNTIL (tfp_nextchar<>' ');πEND; {of Tfp_Skip}ππ{---------------------------------------------------------}π{----This Routine does some trivial check & }π{ Inits Tfp_State_Ptr^ }π{---------------------------------------------------------}ππPROCEDURE Tfp_check(s : STRING;p : tfp_state_ptr);ππVARπ i,j : INTEGER;ππBEGINπ WITH p^ DOπ BEGINπ tfp_lp:=0;ππ {----Test for match on numbers of ( and ) }π j:=0;π FOR i:=1 TO Length(s) DOπ CASE s[i] OFπ '(' : Inc(j);π ')' : Dec(j);π END;ππ IF (j=0)π THENπ {----Continue init}π BEGINπ {----Add a CHR(0) as an EOLN marker}π tfp_line:=s+#00;π Tfp_skip(p);ππ {----Try parsing if any characters left}π IF (tfp_line[tfp_lp]=#00) THEN Tfp_seternr(6);π ENDπ ELSE Tfp_seternr(3);π END;πEND; {of Tfp_Check}ππ{---------------------------------------------------------}π{ Number = Real (Bv 23.4E-5) }π{ Integer (Bv -45) }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_number(p : tfp_state_ptr) : REAL;ππVARπ temp : STRING;π err : INTEGER;π value : REAL;ππBEGINπ WITH p^ DOπ BEGINπ {----Correct .xx to 0.xx}π IF (tfp_nextchar='.')π THEN temp:='0'+tfp_nextcharπ ELSE temp:=tfp_nextchar;ππ Tfp_newchar(p);ππ {----Correct ±.xx to ±0.xx}π IF (Length(temp)=1) ANDπ (temp[1] IN ['+','-']) ANDπ (tfp_nextchar='.')π THEN temp:=temp+'0';ππ WHILE tfp_nextchar IN ['0'..'9','.','E'] DOπ BEGINπ temp:=temp+tfp_nextchar;π IF (tfp_nextchar='E')π THENπ BEGINπ {----Correct ±xxx.E to ±xxx.0E}π IF (temp[Length(temp)-1]='.')π THEN Insert('0',temp,Length(temp));π Tfp_newchar(p);π IF (tfp_nextchar IN ['+','-'])π THENπ BEGINπ temp:=temp+tfp_nextchar;π Tfp_newchar(p);π END;π ENDπ ELSE Tfp_newchar(p);π END;ππ {----Skip trailing spaces}π IF (tfp_nextchar=' ')π THEN Tfp_skip(p);ππ {----Correct ±xx. to ±xx.0 but NOT ±xxE±yy.}π IF (temp[Length(temp)]='.') ANDπ (Pos('E',temp)=0)π THEN temp:=temp+'0';ππ Val(temp,value,err);ππ IF (err<>0) THEN Tfp_seternr(1);π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_number:=valueπ ELSE Tfp_eval_number:=0;ππEND; {of Tfp_Eval_Number}ππ{---------------------------------------------------------}π{ Factor = Number }π{ (External) Function() }π{ (External) Function(Expr) }π{ (External) Function(Expr,Expr) }π{ External Var Real }π{ External Var Integer }π{ External Var Boolean }π{ External Var realstring }π{ (R_Expr) }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_b_expr(p : tfp_state_ptr) : REAL; forward;ππFUNCTION Tfp_eval_factor(p : tfp_state_ptr) : REAL;ππVARπ ferr : BOOLEAN;π param : INTEGER;π dummy : tfp_rarray;π value,π dummy1,π dummy2 : REAL;π temp : tfp_fname;π e,π i,π index : INTEGER;π temps : STRING;π tmpstate : tfp_state_ptr;ππBEGINπ WITH p^ DOπ CASE tfp_nextchar OFπ '+' : BEGINπ Tfp_newchar(p);π value:=+Tfp_eval_factor(p);π END;ππ '-' : BEGINπ Tfp_newchar(p);π value:=-Tfp_eval_factor(p);π END;ππ '0'..π '9',π '.' : value:=Tfp_eval_number(p);ππ 'A'..π 'Z' : BEGINπ ferr:=true;π temp:=tfp_nextchar;π Tfp_skip(p);π WHILE tfp_nextchar IN ['0'..'9','_','A'..'Z'] DOπ BEGINπ temp:=temp+tfp_nextchar;π Tfp_skip(p);π END;ππ {----Seek function and CALL it}π {$R-}π FOR index:=1 TO fiesiz DOπ WITH fiearr^[index] DOπ IF (tfp_fname=temp) THENπ BEGINπ ferr:=false;ππ CASE tfp_ftype OFππ {----Function or Function()}π tfp_noparm : IF (tfp_nextchar='(')π THENπ BEGINπ Tfp_skip(p);ππ IF (tfp_nextchar<>')')π THEN Tfp_seternr(14);ππ Tfp_skip(p);π END;ππ {----Function(r)}π tfp_1real : IF (tfp_nextchar='(')π THENπ BEGINπ Tfp_skip(p);ππ dummy1:=Tfp_eval_b_expr(p);ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>')')π THEN Tfp_seternr(14);ππ Tfp_skip(p); {----Dump the ')'}π ENDπ ELSE Tfp_seternr(14);ππ {----Function(r1,r2)}π tfp_2real : IF (tfp_nextchar='(')π THENπ BEGINπ Tfp_skip(p);ππ dummy1:=Tfp_eval_b_expr(p);ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>',')π THEN Tfp_seternr(14);ππ Tfp_skip(p); {----Dump the ','}π dummy2:=Tfp_eval_b_expr(p);ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>')')π THEN Tfp_seternr(14);ππ Tfp_skip(p); {----Dump the ')'}π ENDπ ELSE Tfp_seternr(14);ππ {----Function(r,n)}π tfp_nreal : IF (tfp_nextchar='(')π THENπ BEGINπ param:=0;ππ Tfp_skip(p);π dummy[param]:=Tfp_eval_b_expr(p);ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>',')π THEN Tfp_seternr(14)π ELSEπ WHILE (tfp_ernr=0) ANDπ (tfp_nextchar=',') ANDπ (param<tfp_maxparm-1) DOπ BEGINπ Tfp_skip(p); {----Dump the ','}π Inc(param);π dummy[param]:=Tfp_eval_b_expr(p);π END;ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>')')π THEN Tfp_seternr(14);ππ Tfp_skip(p); {----Dump the ')'}π ENDπ ELSE Tfp_seternr(14);ππ {----Real Var}π tfp_realvar : dummy1:=REAL(tfp_faddr^);ππ {----Integer Var}π tfp_intvar : dummy1:=1.0*INTEGER(tfp_faddr^);ππ {----Boolean Var}π tfp_boolvar : dummy1:=1.0*Ord(BOOLEAN(tfp_faddr^));ππ {----Real string Var}π tfp_strvar : BEGINπ temps:=STRING(tfp_faddr^);π IF (Maxavail>=Sizeof(tfp_parse_state))π THENπ BEGINπ New(tmpstate);π Tfp_check(temps,tmpstate);π dummy1:=Tfp_eval_b_expr(tmpstate);π Dispose(tmpstate);π ENDπ ELSE Tfp_seternr(15);π END;π END;ππ IF (tfp_ernr=0)π THENπ BEGINπ glueptr:=tfp_faddr;ππ CASE tfp_ftype OFπ tfp_noparm : value:=Tfp_call_noparm;π tfp_1real : value:=Tfp_call_1real(dummy1);π tfp_2real : value:=Tfp_call_2real(dummy1,dummy2);π tfp_nreal : value:=Tfp_call_nreal(dummy,param);π tfp_realvar,π tfp_intvar,π tfp_boolvar,π tfp_strvar : value:=dummy1;π END;π END;π END;π {$R+}ππ IF (ferr=true)π THEN Tfp_seternr(2);π END;ππ '(' : BEGINπ Tfp_skip(p);ππ value:=Tfp_eval_b_expr(p);ππ IF (tfp_ernr=0) ANDπ (tfp_nextchar<>')')π THEN Tfp_seternr(3);ππ Tfp_skip(p); {----Dump the ')'}π END;ππ ELSE Tfp_seternr(2);π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_factor:=valueπ ELSE Tfp_eval_factor:=0;ππEND; {of Tfp_Eval_factor}ππ{---------------------------------------------------------}π{ Term = Factor ^ Factor }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_term(p : tfp_state_ptr) : REAL;ππVARπ value,π exponent,π dummy,π base : REAL;ππBEGINπ WITH p^ DOπ BEGINπ value:=Tfp_eval_factor(p);ππ WHILE (tfp_ernr=0) AND (tfp_nextchar='^') DOπ BEGINπ Tfp_skip(p);ππ exponent:=Tfp_eval_factor(p);ππ base:=value;π IF (tfp_ernr=0) AND (base=0)π THEN value:=0π ELSEπ BEGINππ {----Over/Underflow Protected}π dummy:=exponent*Ln(Abs(base));π IF (dummy<=Ln(tfp_maxreal))π THEN value:=Exp(dummy)π ELSE Tfp_seternr(11);π END;ππ IF (tfp_ernr=0) AND (base<0)π THENπ BEGINπ {----Allow only whole number exponents,π others will result in complex numbers}π IF (Int(exponent)<>exponent)π THEN Tfp_seternr(4);ππ IF (tfp_ernr=0) AND Odd(Tfp_round(exponent))π THEN value:=-value;π END;π END;π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_term:=valueπ ELSE Tfp_eval_term:=0;ππEND; {of Tfp_Eval_term}ππ{---------------------------------------------------------}π{----Subterm = Term * Term }π{ Term / Term }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_subterm(p : tfp_state_ptr) : REAL;ππVARπ value,π dummy : REAL;ππBEGINπ WITH p^ DOπ BEGINπ value:=Tfp_eval_term(p);ππ WHILE (tfp_ernr=0) AND (tfp_nextchar IN ['*','/']) DOπ CASE tfp_nextchar OFππ {----Over/Underflow Protected}π '*' : BEGINπ Tfp_skip(p);ππ dummy:=Tfp_eval_term(p);ππ IF (tfp_ernr<>0) ORπ (value=0) ORπ (dummy=0)π THEN value:=0π ELSEπ IF (Abs( Ln(Abs(value)) +π Ln(Abs(dummy)) ) < Ln(tfp_maxreal))π THEN value:= value * dummyπ ELSE Tfp_seternr(11);π END;ππ {----Over/Underflow Protected}π '/' : BEGINπ Tfp_skip(p);ππ dummy:=Tfp_eval_term(p);ππ IF (tfp_ernr=0)π THENπ BEGINππ {----Division by ZERO Protected}π IF (dummy<>0)π THENπ BEGINππ {----Underflow Protected}π IF (value<>0)π THENπ BEGINπ IF (Abs( Ln(Abs(value)) -π Ln(Abs(dummy)) ) < Ln(tfp_maxreal))π THEN value:=value/dummyπ ELSE Tfp_seternr(11)π ENDπ ELSE value:=0;π ENDπ ELSE Tfp_seternr(9);π END;π END;π END;π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_subterm:=valueπ ELSE Tfp_eval_subterm:=0;πEND;{of Tfp_Eval_subterm}ππ{---------------------------------------------------------}π{ Real Expr = Subterm + Subterm }π{ Subterm - Subterm }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_r_expr(p : tfp_state_ptr) : REAL;ππVARπ dummy,π dummy2,π value : REAL;ππBEGINπ WITH p^ DOπ BEGINπ value:=Tfp_eval_subterm(p);ππ WHILE (tfp_ernr=0) AND (tfp_nextchar IN ['+','-']) DOπ CASE tfp_nextchar OFππ '+' : BEGINπ Tfp_skip(p);ππ dummy:=Tfp_eval_subterm(p);ππ IF (tfp_ernr=0)π THENπ BEGINππ {----Overflow Protected}π IF (Abs( (value/10) + (dummy/10) ) < (tfp_maxreal/10))π THEN value:=value+dummyπ ELSE Tfp_seternr(11);π END;π END;ππ '-' : BEGINπ Tfp_skip(p);π dummy2:=value;ππ dummy:=Tfp_eval_subterm(p);ππ IF (tfp_ernr=0)π THENπ BEGINππ {----Overflow Protected}π IF (Abs( (value/10) - (dummy/10) )<(tfp_maxreal/10))π THEN value:=value-dummyπ ELSE Tfp_seternr(11);ππ {----Underflow Protected}π IF (value=0) AND (dummy<>dummy2)π THEN Tfp_seternr(11);π END;π END;π END;ππ {----at this point the current char must be }π { 1. the eoln marker or }π { 2. a right bracket }π { 3. start of a boolean operator }ππ IF NOT (tfp_nextchar IN [#00,')','>','<','=',','])π THEN Tfp_seternr(2);π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_r_expr:=valueπ ELSE Tfp_eval_r_expr:=0;πEND; {of Tfp_Eval_R_Expr}ππ{---------------------------------------------------------}π{ Boolean Expr = R_Expr < R_Expr }π{ R_Expr <= R_Expr }π{ R_Expr <> R_Expr }π{ R_Expr = R_Expr }π{ R_Expr >= R_Expr }π{ R_Expr > R_Expr }π{---------------------------------------------------------}ππFUNCTION Tfp_eval_b_expr(p : tfp_state_ptr) : REAL;ππVARπ value : REAL;ππBEGINπ WITH p^ DOπ BEGINπ value:=Tfp_eval_r_expr(p);ππ IF (tfp_ernr=0) AND (tfp_nextchar IN ['<','>','=']) THENπ CASE tfp_nextchar OFππ '<' : BEGINπ Tfp_skip(p);π IF (tfp_nextchar IN ['>','='])π THENπ CASE tfp_nextchar OFπ '>' : BEGINπ Tfp_skip(p);π IF (value<>Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π END;ππ '=' : BEGINπ Tfp_skip(p);π IF (value<=Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π END;π ENDπ ELSEπ BEGINπ IF (value<Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π END;π END;ππ '>' : BEGINπ Tfp_skip(p);π IF (tfp_nextchar='=')π THENπ BEGINπ Tfp_skip(p);π IF (value>=Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π ENDπ ELSEπ BEGINπ IF (value>Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π END;π END;ππ '=' : BEGINπ Tfp_skip(p);π IF (value=Tfp_eval_r_expr(p))π THEN value:=tfp_trueπ ELSE value:=tfp_false;π END;π END;π END;ππ IF (tfp_ernr=0)π THEN Tfp_eval_b_expr:=valueπ ELSE Tfp_eval_b_expr:=0.0;πEND; {of Tfp_Eval_B_Expr}ππ{---------------------------------------------------------}ππFUNCTION Tfp_parse2real(s : STRING): REAL;ππVARπ value : REAL;ππBEGINπ tfp_erpos:=0;π tfp_ernr :=0;ππ IF Maxavail>=Sizeof(tfp_parse_state)π THENπ BEGINπ New(p);π Tfp_check(s,p);ππ IF (tfp_ernr=0)π THEN value:=Tfp_eval_b_expr(p);ππ Dispose(p);π ENDπ ELSE Tfp_seternr(15);ππ IF (tfp_ernr<>0)π THEN Tfp_parse2real:=0.0π ELSE Tfp_parse2real:=value;ππEND; {of Tfp_Parse2Real}ππ{---------------------------------------------------------}ππFUNCTION Tfp_parse2str(s : STRING;m,n : INTEGER) : STRING;ππVARπ r : REAL;π tmp : STRING;ππBEGINπ r:=Tfp_parse2real(s);π IF (tfp_ernr=0)π THEN Str(r:m:n,tmp)π ELSE tmp:='';π Tfp_parse2str:=tmp;πEND; {of Tfp_Parse2str}ππ{---------------------------------------------------------}ππFUNCTION Tfp_errormsg(nr : INTEGER) : STRING;ππBEGINπ CASE nr OFπ 0 : Tfp_errormsg:='Result ok'; {Error 0 }π 1 : Tfp_errormsg:='Invalid format of a number'; {Error 1 }π 2 : Tfp_errormsg:='Unkown function'; {Error 2 }π 3 : Tfp_errormsg:='( ) mismatch'; {Error 3 }π 4 : Tfp_errormsg:='Real exponent -> complex number'; {Error 4 }π 5 : Tfp_errormsg:='TAN( (2n+1)*PI/2 ) not defined'; {Error 5 }π 6 : Tfp_errormsg:='Empty string'; {Error 6 }π 7 : Tfp_errormsg:='LN(x) or LOG(x) for x<=0 -> complex number'; {Error 7 }π 8 : Tfp_errormsg:='SQRT(x) for x<0 -> complex number'; {Error 8 }π 9 : Tfp_errormsg:='Divide by zero'; {Error 9 }π 10 : Tfp_errormsg:='To many function or constants'; {Error 10}π 11 : Tfp_errormsg:='Intermediate result out of range'; {Error 11}π 12 : Tfp_errormsg:='Illegal characters in functionname'; {Error 12}π 13 : Tfp_errormsg:='Not a boolean expression'; {Error 13}π 14 : Tfp_errormsg:='Wrong number of parameters'; {Error 14}π 15 : Tfp_errormsg:='Memory problems'; {Error 15}π 16 : Tfp_errormsg:='Not enough functions or constants'; {Error 16}π 17 : Tfp_errormsg:='Csc( n*PI ) not defined'; {Error 17}π 18 : Tfp_errormsg:='Sec( (2n+1)*PI/2 ) not defined'; {Error 18}π 19 : Tfp_errormsg:='Cot( n*PI ) not defined'; {Error 19}π 20 : Tfp_errormsg:='Parameter to large'; {Error 20}π 21 : Tfp_errormsg:='Csch(0) not defined'; {Error 21}π 22 : Tfp_errormsg:='Coth(0) not defined'; {Error 22}π 23 : Tfp_errormsg:='ArcCosh(x) not defined for x<1'; {Error 23}π 24 : Tfp_errormsg:='ArcTanh(x) not defined for Abs(x)=>1'; {Error 24}π 25 : Tfp_errormsg:='Arccsch(0) not defined'; {Error 25}π 26 : Tfp_errormsg:='Arcsech(x) not defined for x<=0 or x>1'; {Error 26}π 27 : Tfp_errormsg:='Arccoth(x) not defined for Abs(x)<=1'; {Error 27}π ELSE Tfp_errormsg:='Unkown error'; {Error xx}π END;πEND; {of Tfp_ermsg}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_init(no : WORD);ππBEGINπ IF (maxfie>0)π THEN Freemem(fiearr,maxfie*Sizeof(tfp_fie_typ));ππ maxfie:=0;π fiesiz:=0;ππ IF (Maxavail>=(no*Sizeof(tfp_fie_typ))) AND (no>0)π THENπ BEGINπ getmem(fiearr,no*Sizeof(tfp_fie_typ));π maxfie:=no;π ENDπ ELSE Tfp_seternr(15);πEND; {of Tfp_Init}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_expand(no : WORD);ππVARπ temp : ^tfp_fieptr;ππBEGINπ IF (maxfie>0) AND (no>0)π THENπ BEGINπ IF (Maxavail>=(maxfie+no)*Sizeof(tfp_fie_typ))π THENπ BEGINπ getmem(temp,(maxfie+no)*Sizeof(tfp_fie_typ));π Move(fiearr^,temp^,maxfie*Sizeof(tfp_fie_typ));π Freemem(fiearr,maxfie*Sizeof(tfp_fie_typ));π fiearr:=POINTER(temp);π maxfie:=maxfie+no;π fiesiz:=fiesiz;π ENDπ ELSE Tfp_seternr(15)π ENDπ ELSE Tfp_init(no);πEND; {of Tfp_Expand}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_keep(no : WORD);ππBEGINπ IF (maxfie<no)π THEN Tfp_seternr(16)π ELSE maxfie:=no;πEND; {of Tfp_Keep}ππ{---------------------------------------------------------}ππFUNCTION Tfp_noobj : WORD;ππBEGINπ Tfp_noobj:=maxfie;πEND; {of Tfp_Noobj}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addobj(adres : POINTER;name : tfp_fname;ftype : tfp_ftype);ππVARπ i : INTEGER;ππBEGINπ{$R-}π IF (fiesiz<maxfie)π THENπ BEGINπ Inc(fiesiz);π WITH fiearr^[fiesiz] DOπ BEGINπ tfp_faddr:=adres;π tfp_fname:=name;π FOR i:=1 TO Length(tfp_fname) DOπ IF (Upcase(tfp_fname[i]) IN ['0'..'9','_','A'..'Z'])π THEN tfp_fname[i]:=Upcase(tfp_fname[i])π ELSE Tfp_seternr(12);ππ IF (Length(tfp_fname)>0) ANDπ NOT (tfp_fname[1] IN ['A'..'Z'])π THEN Tfp_seternr(12);ππ tfp_ftype:=ftype;π ENDπ ENDπ ELSE Tfp_seternr(10);π{$R+}πEND; {of Tfp_Addobject}ππ{---------------------------------------------------------}π{----Internal Functions }π{---------------------------------------------------------}ππ{$F+}ππFUNCTION Xabs(VAR r : REAL) : REAL;ππBEGINπ Xabs:=Abs(r);πEND; {of xABS}ππ{---------------------------------------------------------}ππFUNCTION Xand(VAR lu_r;VAR n : INTEGER) : REAL;ππVARπ r : REAL;π i : INTEGER;ππBEGINπ FOR i:=0 TO n DOπ IF (tfp_rarray(lu_r)[i]<>tfp_false) ANDπ (tfp_rarray(lu_r)[i]<>tfp_true)π THENπ BEGINπ IF (tfp_ernr=0)π THEN Tfp_seternr(13);π END;ππ IF (tfp_ernr=0) AND (n>0)π THENπ BEGINπ r:=tfp_true*Ord(tfp_rarray(lu_r)[0]=tfp_true);π FOR i:=1 TO n DOπ r:=tfp_true*Ord( (r=tfp_true) AND (tfp_rarray(lu_r)[i]=tfp_true))π ENDπ ELSE Tfp_seternr(14);ππ IF tfp_ernr=0π THEN Xand:=rπ ELSE Xand:=0.0;πEND; {of xAND}ππ{---------------------------------------------------------}ππFUNCTION Xarctan(VAR r : REAL) : REAL;ππBEGINπ Xarctan:=Arctan(r);πEND; {of xArctan}ππ{---------------------------------------------------------}ππFUNCTION Xcos(VAR r : REAL) : REAL;ππBEGINπ Xcos:=Cos(r);πEND; {of xCos}ππ{---------------------------------------------------------}ππFUNCTION Xdeg(VAR r : REAL) : REAL;ππBEGINπ Xdeg:=(r/pi)*180;πEND; {of xDEG}ππ{---------------------------------------------------------}ππFUNCTION Xe : REAL;ππBEGINπ Xe:=Exp(1);πEND; {of xE}ππ{---------------------------------------------------------}ππFUNCTION Xexp(VAR r : REAL) : REAL;ππBEGINπ Xexp:=0;π IF (Abs(r)<Ln(tfp_maxreal))π THEN Xexp:=Exp(r)π ELSE Tfp_seternr(11);πEND; {of xExp}ππ{---------------------------------------------------------}ππFUNCTION Xfalse : REAL;ππBEGINπ Xfalse:=tfp_false;πEND; {of xFalse}ππ{---------------------------------------------------------}ππFUNCTION Xfrac(VAR r : REAL) : REAL;ππBEGINπ Xfrac:=Frac(r);πEND; {of xFrac}ππ{---------------------------------------------------------}ππFUNCTION Xint(VAR r : REAL) : REAL;ππBEGINπ Xint:=Int(r);πEND; {of xInt}ππ{---------------------------------------------------------}ππFUNCTION Xln(VAR r : REAL) : REAL;ππBEGINπ Xln:=0;π IF (r>0)π THEN Xln:=Ln(r)π ELSE Tfp_seternr(7);πEND; {of xLn}ππ{---------------------------------------------------------}ππFUNCTION Xlog(VAR r : REAL) : REAL;ππBEGINπ Xlog:=0;π IF (r>0)π THEN Xlog:=Ln(r)/ln(10)π ELSE Tfp_seternr(7);πEND; {of xLog}ππ{---------------------------------------------------------}ππFUNCTION Xmax(VAR lu_r;VAR n : INTEGER) : REAL;ππVARπ max : REAL;π i : INTEGER;ππBEGINπ max:=tfp_rarray(lu_r)[0];π FOR i:=1 TO n DOπ IF (tfp_rarray(lu_r)[i]>max)π THEN max:=tfp_rarray(lu_r)[i];π Xmax:=max;πEND; {of xMax}ππ{---------------------------------------------------------}ππFUNCTION Xmin(VAR lu_r;VAR n : INTEGER) : REAL;ππVARπ min : REAL;π i : INTEGER;ππBEGINπ min:=tfp_rarray(lu_r)[0];π FOR i:=1 TO n DOπ IF (tfp_rarray(lu_r)[i]<min)π THEN min:=tfp_rarray(lu_r)[i];π Xmin:=min;πEND; {of xMin}ππ{---------------------------------------------------------}ππFUNCTION Xior(VAR lu_r;VAR n : INTEGER) : REAL;ππVARπ r : REAL;π i : INTEGER;ππBEGINπ FOR i:=0 TO n DOπ IF (tfp_rarray(lu_r)[i]<>tfp_false) ANDπ (tfp_rarray(lu_r)[i]<>tfp_true)π THENπ BEGINπ IF (tfp_ernr=0)π THEN Tfp_seternr(13);π END;ππ IF (tfp_ernr=0) ANDπ (n>0)π THENπ BEGINπ r:=tfp_true*Ord(tfp_rarray(lu_r)[0]=tfp_true);π FOR i:=1 TO n DOπ r:=tfp_true*Ord((r=tfp_true) OR (tfp_rarray(lu_r)[i]=tfp_true))π ENDπ ELSE Tfp_seternr(14);ππ IF tfp_ernr=0π THEN Xior:=rπ ELSE Xior:=Tfp_false;πEND; {of xIor}ππ{---------------------------------------------------------}ππFUNCTION Xpi : REAL;ππBEGINπ Xpi:=Pi;πEND; {of xPi}ππ{---------------------------------------------------------}ππFUNCTION Xrad(VAR r : REAL) : REAL;ππBEGINπ Xrad:=(r/180)*Pi;πEND; {of xRad}ππ{---------------------------------------------------------}ππFUNCTION Xround(VAR r : REAL) : REAL;ππBEGINπ IF (Abs(r)<tfp_maxlongint)π THEN Xround:=Tfp_round(r)π ELSE Xround:=r;πEND; {of xRound}ππ{---------------------------------------------------------}ππFUNCTION Xsgn(VAR r : REAL) : REAL;ππBEGINπ IF (r>=0)π THEN Xsgn:=+1π ELSE Xsgn:=-1;πEND; {of xSgn}ππ{---------------------------------------------------------}ππFUNCTION Xsin(VAR r : REAL) : REAL;ππBEGINπ Xsin:=Sin(r);πEND; {of xSin}ππ{---------------------------------------------------------}ππFUNCTION Xsqr(VAR r : REAL) : REAL;ππBEGINπ Xsqr:=0;π IF (Abs(r)>0)π THENπ BEGINπ IF ( Abs(2*Ln(Abs(r))) )<Ln(tfp_maxreal)π THEN Xsqr:=Exp( 2*Ln(Abs(r)) )π ELSE Tfp_seternr(11);π END;πEND; {of xSqr}ππ{---------------------------------------------------------}ππFUNCTION Xsqrt(VAR r : REAL) : REAL;ππBEGINπ Xsqrt:=0;π IF (r>=0)π THEN Xsqrt:=Sqrt(r)π ELSE Tfp_seternr(8);πEND; {of xSqrt}ππ{---------------------------------------------------------}ππFUNCTION Xtan(VAR r : REAL) : REAL;ππBEGINπ Xtan:=0;π IF (Cos(r)=0)π THEN Tfp_seternr(5)π ELSE Xtan:=Sin(r)/cos(r);πEND; {of xTan}ππ{---------------------------------------------------------}ππFUNCTION Xtrue : REAL;ππBEGINπ Xtrue:=tfp_true;πEND; {of xTrue}ππ{---------------------------------------------------------}ππFUNCTION Xxor(VAR r1,r2 : REAL) : REAL;ππBEGINπ Xxor:=tfp_false;π IF ((r1<>tfp_false) AND (r1<>tfp_true)) ORπ ((r2<>tfp_false) AND (r2<>tfp_true))π THENπ BEGINπ IF (tfp_ernr=0)π THEN Tfp_seternr(13);π ENDπ ELSE Xxor:=tfp_true*Ord((r1=tfp_true) XOR (r2=tfp_true));πEND; {of xXOR}ππ{---------------------------------------------------------}π{----Hyperbolic, reciproce and inverse goniometric }π{ functions }π{---------------------------------------------------------}ππFunction xCsc(VAR r: Real): Real;ππBegin;π xCsc:=0;π IF (Sin(r)=0)π THEN Tfp_seternr(17)π ELSE xCsc:=1/Sin(r);πEnd; {xCsc}ππ{---------------------------------------------------------}ππFunction xSec(VAR r: Real): Real;ππBegin;π xSec:=0;π IF (Cos(r)=0)π THEN Tfp_seternr(18)π ELSE xSec:=1/Cos(r);πEnd; {xSec}ππ{---------------------------------------------------------}ππFunction xCot(VAR r : Real): Real;ππBegin;π xCot:=0;π IF (Sin(r)=0)π THEN Tfp_seternr(19)π ELSE xCot:=Cos(r)/Sin(r);πEnd; {xCot}ππ{---------------------------------------------------------}ππFUNCTION xCosh(VAR r : REAL) : REAL;ππBEGINπ xCosh:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSE xCosh:=(Exp(r)+Exp(-r))/2;πEND; {of xCosh}ππ{---------------------------------------------------------}ππFUNCTION xSinh(VAR r : REAL) : REAL;ππBEGINπ xSinh:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSE xSinh:=(Exp(r)-Exp(-r))/2;πEND; {of xSinh}ππ{---------------------------------------------------------}ππFUNCTION xTanh(VAR r : REAL) : REAL;ππBEGINπ xTanh:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSE xTanh:=(Exp(r)-Exp(-r))/(Exp(r)+Exp(-r));πEND; {of xTanh}ππ{---------------------------------------------------------}ππFUNCTION xCsch(VAR r : REAL) : REAL;ππBEGINπ xCsch:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSEπ BEGINπ IF (r=0)π THEN Tfp_seternr(21)π ELSE xCsch:=2/(Exp(r)-Exp(-r))π END;πEND; {of xCsch}ππ{---------------------------------------------------------}ππFUNCTION xSech(VAR r : REAL) : REAL;ππBEGINπ xSech:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSE xSech:=2/(Exp(r)+Exp(-r));πEND; {of xSech}ππ{---------------------------------------------------------}ππFUNCTION xCoth(VAR r : REAL) : REAL;ππBEGINπ xCoth:=0;π IF (Abs(r)>Ln(tfp_maxreal))π THEN Tfp_seternr(20)π ELSEπ BEGINπ IF (r=0)π THEN Tfp_seternr(22)π ELSE xCoth:=(Exp(r)+Exp(-r))/(Exp(r)-Exp(-r))π END;πEND; {of xCoth}ππ{---------------------------------------------------------}ππFUNCTION xArcsinh(VAR r : REAL) : REAL;ππBEGINπ xArcsinh:=0;π IF (Abs(r)<SQRT(tfp_maxreal))π THEN xArcsinh:=Ln(r+Sqrt(Sqr(r)+1))π ELSE Tfp_seternr(20)πEND; {of xArcsinh}ππ{---------------------------------------------------------}ππFUNCTION xArccosh(VAR r : REAL) : REAL;ππBEGINπ xArccosh:=0;π IF (Abs(r)<SQRT(tfp_maxreal))π THENπ BEGINπ IF (r>=1)π THEN xArccosh:=ln(r+Sqrt(Sqr(r)-1))π ELSE Tfp_seternr(23);π ENDπ ELSE Tfp_seternr(20)πEND; {of xArccosh}ππ{---------------------------------------------------------}ππFUNCTION xArctanh(VAR r : REAL) : REAL;ππBEGINπ xArctanh:=0;π IF (Abs(r)<1)π THEN xArctanh:=ln( (1+r)/(1-r) )/2π ELSE Tfp_seternr(24)πEND; {of xArctanh}ππ{---------------------------------------------------------}ππFUNCTION xArccsch(VAR r : REAL) : REAL;ππBEGINπ xArccsch:=0;π IF (r<SQRT(Tfp_maxreal))π THENπ BEGINπ IF (r<>0)π THEN xArccsch:=Ln( (1/r) + SQRT( (1/SQR(r))+1))π ELSE Tfp_seternr(25)π ENDπ ELSE Tfp_seternr(20);πEND; {of xArccsch}ππ{---------------------------------------------------------}ππFUNCTION xArcsech(VAR r : REAL) : REAL;ππBEGINπ xArcsech:=0;π IF (r<SQRT(Tfp_maxreal))π THENπ BEGINπ IF (r>0) AND (r<=1)π THEN xArcsech:=Ln( (1/r) + SQRT( (1/SQR(r))-1))π ELSE Tfp_seternr(26)π ENDπ ELSE Tfp_seternr(20)πEND; {of xArcsech}ππ{---------------------------------------------------------}ππFUNCTION xArccoth(VAR r : REAL) : REAL;ππBEGINπ xArccoth:=0;π IF (Abs(r)>1)π THEN xArccoth:=Ln( (r+1)/(r-1) )/2π ELSE Tfp_seternr(27)πEND; {of xArccoth}ππ{$F-}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addgonio;ππBEGINπ Tfp_expand(7);π Tfp_addobj(@xarctan,'ARCTAN',tfp_1real);π Tfp_addobj(@xcos ,'COS' ,tfp_1real);π Tfp_addobj(@xdeg ,'DEG' ,tfp_1real);π Tfp_addobj(@xpi ,'PI' ,tfp_noparm);π Tfp_addobj(@xrad ,'RAD' ,tfp_1real);π Tfp_addobj(@xsin ,'SIN' ,tfp_1real);π Tfp_addobj(@xtan ,'TAN' ,tfp_1real);πEND; {of Tfp_Addgonio}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addlogic;ππBEGINπ Tfp_expand(5);π Tfp_addobj(@xand ,'AND' ,tfp_nreal);π Tfp_addobj(@xfalse ,'FALSE' ,tfp_noparm);π Tfp_addobj(@xior ,'OR' ,tfp_nreal);π Tfp_addobj(@xtrue ,'TRUE' ,tfp_noparm);π Tfp_addobj(@xxor ,'XOR' ,tfp_2real);πEND; {of Tfp_Addlogic}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addmath;ππBEGINπ Tfp_expand(7);π Tfp_addobj(@xabs ,'ABS' ,tfp_1real);π Tfp_addobj(@xexp ,'EXP' ,tfp_1real);π Tfp_addobj(@xe ,'E' ,tfp_noparm);π Tfp_addobj(@xln ,'LN' ,tfp_1real);π Tfp_addobj(@xlog ,'LOG' ,tfp_1real);π Tfp_addobj(@xsqr ,'SQR' ,tfp_1real);π Tfp_addobj(@xsqrt ,'SQRT' ,tfp_1real);πEND; {of Tfp_Addmath}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addmisc;ππBEGINπ Tfp_expand(6);π Tfp_addobj(@xfrac ,'FRAC' ,tfp_1real);π Tfp_addobj(@xint ,'INT' ,tfp_1real);π Tfp_addobj(@xmax ,'MAX' ,tfp_nreal);π Tfp_addobj(@xmin ,'MIN' ,tfp_nreal);π Tfp_addobj(@xround ,'ROUND' ,tfp_1real);π Tfp_addobj(@xsgn ,'SGN' ,tfp_1real);πEND; {of Tfp_Addmisc}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addinvarchyper;ππBEGINπ Tfp_expand(15);π Tfp_addobj(@xcsc ,'CSC' ,tfp_1real);π Tfp_addobj(@xsec ,'SEC' ,tfp_1real);π Tfp_addobj(@xcot ,'COT' ,tfp_1real);ππ Tfp_addobj(@xsinh ,'SINH' ,tfp_1real);π Tfp_addobj(@xcosh ,'COSH' ,tfp_1real);π Tfp_addobj(@xtanh ,'TANH' ,tfp_1real);ππ Tfp_addobj(@xcsch ,'CSCH' ,tfp_1real);π Tfp_addobj(@xsech ,'SECH' ,tfp_1real);π Tfp_addobj(@xcoth ,'COTH' ,tfp_1real);ππ Tfp_addobj(@xarcsinh,'ARCSINH',tfp_1real);π Tfp_addobj(@xarccosh,'ARCCOSH',tfp_1real);π Tfp_addobj(@xarctanh,'ARCTANH',tfp_1real);ππ Tfp_addobj(@xarccsch,'ARCCSCH',tfp_1real);π Tfp_addobj(@xarcsech,'ARCSECH',tfp_1real);π Tfp_addobj(@xarccoth,'ARCCOTH',tfp_1real);πEnd; {of Add_invandhyper}ππ{---------------------------------------------------------}ππPROCEDURE Tfp_addall;ππBEGINπ Tfp_addgonio;π Tfp_addlogic;π Tfp_addmath;π Tfp_addmisc;π Tfp_addinvarchyper;πEND; {of Tfp_addall}ππ{---------------------------------------------------------}ππBEGINπ{----Module Init}π tfp_erpos :=0;π tfp_ernr :=0;π fiesiz:=0;π maxfie:=0;π fiearr:=NIL;πEND.π 5 08-25-9409:08ALL BOB SCHOR FFT Algorithm in Pascal SWAG9408 ⌡&ª» 122 ₧ {π─ Area: U-PASCAL |61 ────────────────────────────────────────────────────π Msg#: 5727 Date: 07-05-94 08:14π From: Bschor@vms.cis.pitt.edu Read: Yes Replied: Noπ To: All Mark:π Subj: FFT Algorithm in Pascalπ──────────────────────────────────────────────────────────────────────────────πFrom: bschor@vms.cis.pitt.eduππ Over the past several weeks, there have been questions about the FastπFourier Transform, including requests for a version of the algorithm. Theπfollowing is one such implementation, optimized for clarity (??) at theπpossible expense of a few percentage points in speed (it's pretty darnπfast). It is written in "vanilla" Pascal, so it should work with allπvariants of the language.ππ Note that buried in the comments is a reasonable reference for theπalgorithm.π }πππPROGRAM fft (input, output);ππ {****************************************}π { }π { Bob Schor }π { Eye and Ear Institute }π { 203 Lothrop Street }π { Pittsburgh, PA 15213 }π { }π {****************************************}ππ { test routine for FFT in Pascal -- includes real and complex }ππ { Version 1.6 -- first incarnation }π { Version 10.7 -- upgrade, allow in-place computation of coefficients }π { Version 14.6 -- comments added for didactic purposes }π πCONSTπ version = 'FFT Version 14.6';π πCONSTπ maxarraysize = 128;π halfmaxsize = 64;π maxfreqsize = 63;πTYPEπ dataindextype = 1 .. maxarraysize;π cmpxindextype = 1 .. halfmaxsize;π freqindextype = 1 .. maxfreqsize;π complex = RECORDπ realpart, imagpart : realπ END;π dataarraytype = RECORDπ CASE (r, c) OFπ r : (rp : ARRAY [dataindextype] OF real);π c : (cp : ARRAY [cmpxindextype] OF complex)π END;π cstermtype = RECORDπ cosineterm, sineterm : realπ END;π fouriertype = RECORDπ dcterm : real;π noiseterm : real;π freqterms : ARRAY [freqindextype] OF cstermtypeπ END;π mixedtype = RECORDπ CASE (dtype, ctype) OFπ dtype : (dataslot : dataarraytype);π ctype : (coefslot : fouriertype)π END;π πCONSTπ twopi = 6.2831853;πVARπ data : dataarraytype;π didx : dataindextype;π fidx : freqindextype;π coefficients : fouriertype;π mixed : mixedtype;π π { A note on declarations, above. Pascal does not have a base type ofπ "complex", but it is fairly simple, given the strong typing in theπ language, to define such a type. One needs to write procedures (seeπ below) that implement the common arithmetic operators. Functionsπ would be even better, from a logical standpoint, but the languageπ standard does not permit returning a record type from a function.π . The FFT, strictly speaking, is a technique for transforming aπ complex array of points-in-time into a complex array of points-in-π Fourier space (complex numbers that represent the gain and phase ofπ the response at discrete frequencies). One typically has data,π representing samples taken at some fixed sampling rate, for whichπ one wants the Fourier transform, to compute a power spectrum, forπ example. Such data, of course, are "real" quantities. One couldπ take these N points, make them the real part of a complex array ofπ size N (setting the imaginary part to zero), and take the FFT.π However, in the interest of speed (the first F of FFT means "fast",π after all), one can also do a trick where the N "real" points areπ identified with the real, imaginary, real, imaginary, etc. points ofπ a complex array of size N/2. The FFT now takes about half the time,π and one needs to do some final twiddling to obtain the sine/cosineπ coefficients of the size N real array from the coefficients of theπ size N/2 complex array.π . To clarify the dual interpretation of the data array as eitherπ N reals or N/2 complex points, the tagged type "dataarraytype" wasπ defined. On input, it represents the complex data; on output from theπ complex FFT, it represents the complex Fourier coefficients. A finalπ transformation on these complex coefficients can convert them into aπ series of real sine/cosine terms; for this purpose, the tagged typeπ "mixed" was defined for the real FFT.π . Finally, note that this, and most, FFT routines get theirπ speed when the number of points is a power of 2. This is becauseπ the speed comes from a divide-and-conquer approach -- to do an FFTπ of N points, do two FFTs of N/2 points and combine the results. }π π π PROCEDURE fftofreal (VAR mixed : mixedtype;π realpoints : integer);π π { This routine performs a forward Fourier transform of an arrayπ "mixed", which on input is assumed to consist of "realpoints" dataπ points and on output consists of a set of Fourier coefficients (aπ DC term, (N/2 - 1) sine and cosine terms, and a residual "noise"π term). }π π CONSTπ twopi = 6.2831853;π VARπ index, minusindex : freqindextype;π temp1, temp2, temp3, w : complex;π baseangle : real;π π { The following procedures implement complex arithmetic -- }π π PROCEDURE cadd (a, b : complex;π VAR c : complex);π π { c := a + b }π π BEGIN { cadd }π WITH c DOπ BEGINπ realpart := a.realpart + b.realpart;π imagpart := a.imagpart + b.imagpartπ ENDπ END;π π PROCEDURE csubtract (a, b : complex;π VAR c : complex);π π { c := a - b }π π BEGIN { csubtract }π WITH c DOπ BEGINπ realpart := a.realpart - b.realpart;π imagpart := a.imagpart - b.imagpartπ ENDπ END;π π PROCEDURE cmultiply (a, b : complex;π VAR c : complex);ππ { c := a * b }π π BEGIN { cmultiply }π WITH c DOπ BEGINπ realpart := a.realpart*b.realpart - a.imagpart*b.imagpart;π imagpart := a.realpart*b.imagpart + b.realpart*a.imagpartπ ENDπ END;π π PROCEDURE conjugate (a : complex;π VAR b : complex);π π { b := a* }π π BEGIN { conjugate }π WITH b DOπ BEGINπ realpart := a.realpart;π imagpart := -a.imagpartπ ENDπ END;π π PROCEDURE forwardfft (VAR data : dataarraytype;π complexpoints : integer);π ππ { The basic FFT is a recursive routine that basically works asπ follows:π 1) The FFT is a linear operator, so the FFT of a sum is simplyπ . the sum of the FFTs of each addend.π 2) The FFT of a time series shifted in time is the FFT of theπ . unshifted series adjusted by a twiddle factor which looksπ . like a (complex) root of 1 (an nth root of unity).π 3) Consider N points, equally spaced in time, for which youπ . want an FFT. Start by splitting the series into odd andπ . even samples, giving you two series with N/2 points,π . equally spaced, but with the second series delayed in timeπ . by one sample. Take the FFT of each series. Using propertyπ . 2), adjust the FFT of the second series for the time delay.π . Now using property 1), since the original N points is simplyπ . the sum of the two N/2 series, the FFT we want is simply theπ . sum of the FFTs of the two sub-series (with the adjustmentπ . in the second for the time delay).π 4) This is essentially a recursive definition. To do an N-pointπ . FFT, do two N/2 point FFTs and combine the answers. All weπ . need to stop the recursion is to know how to do a 2-pointπ . FFT: if a and b are the two (complex) input points, theπ . two-point FFT equations are A := a+b; B := a-b.π 5) The FFT is rarely coded in its fully-recursive form. Itπ . turns out to be fairly simple to "unroll" the recursion andπ . reorder it a bit, which simplifies the computation of theπ . roots-of-unity complex twiddle factors. The only drawbackπ . is that the output array ends up scrambled -- if the arrayπ . indices are represented as going from 0 to M-1, then if oneπ . represents the array index as a binary number, one needs toπ . bit-reverse the number to get the proper place in the array.π . Thus, the next step is to swap values by bit-reversing theπ . indices.π 6) There are numerous references on the FFT. A reasonable oneπ . is "Numerical Recipes" by Press et al., Cambridge Universityπ . Press, which I believe exists in several language flavors. }π π CONSTπ twopi = 6.2831853;π π PROCEDURE docomplextransform;π π VARπ partitionsize, halfsize, offset,π lowindex, highindex : dataindextype;π baseangle, angle : real;π bits : integer;π w, temp : complex;π π BEGIN { docomplextransform }π partitionsize := complexpoints;π WITH data DOπ REPEATπ halfsize := partitionsize DIV 2;π baseangle := twopi/partitionsize;π FOR offset := 1 TO halfsize DOπ BEGINπ angle := baseangle * pred(offset);π w.realpart := cos(angle);π w.imagpart := -sin(angle);π lowindex := offset;π REPEATπ highindex := lowindex + halfsize;π csubtract (cp[lowindex], cp[highindex], temp);π cadd (cp[lowindex], cp[highindex], cp[lowindex]);π cmultiply (temp, w, cp[highindex]);π lowindex := lowindex + partitionsizeπ UNTIL lowindex >= complexpointsπ END;π partitionsize := partitionsize DIV 2π UNTIL partitionsize = 1π END;π π PROCEDURE shufflecoefficients;π π VARπ lowindex, highindex : dataindextype;π bits : integer;π π FUNCTION log2 (index : integer) : integer;π π { Recursive routine, where "index" is assumed a power of 2.π Note the routine will fail (by endless recursion) ifπ "index" <= 0. }π π BEGIN { log2 }π IF index = 1π THEN log2 := 0π ELSE log2 := succ(log2(index DIV 2))π END;ππ FUNCTION bitreversal (index, bits : integer) : integer;π π { Takes an index, in the range 1 .. 2**bits, and computes aπ bit-reversed index in the same range. It first undoes theπ offset of 1, bit-reverses the "bits"-bit binary number,π then redoes the offset. Thus if bits = 4, the range isπ 1 .. 16, and bitreversal (1, 4) = 9,π bitreversal (16, 4) = 16, etc. }π π FUNCTION reverse (bits, stib, bitsleft : integer) : integer;ππ { Recursive bit-reversing function, transforms "bits" intoπ bit-reversed "stib. It's pretty easy to convert this toπ an iterative form, but I think the recursive form isπ easier to understand, and should entail a trivial penaltyπ in speed (in the overall algorithm). }π π BEGIN { reverse }π IF bitsleft = 0π THEN reverse := stibπ ELSEπ IF odd (bits)π THEN reverse := reverse (bits DIV 2, succ (stib * 2),π pred (bitsleft))π ELSE reverse := reverse (bits DIV 2, stib * 2,π pred (bitsleft))π END;ππ BEGIN { bitreversal }π bitreversal := succ (reverse (pred(index), 0, bits))π END;π π PROCEDURE swap (VAR a, b : complex);π π VARπ temp : complex;π π BEGIN { swap }π temp := a;π a := b;π b := tempπ END;π π BEGIN { shufflecoefficients }π bits := log2 (complexpoints);π WITH data DOπ FOR lowindex := 1 TO complexpoints DOπ BEGINπ highindex := bitreversal(lowindex, bits);π IF highindex > lowindexπ THEN swap (cp[lowindex], cp[highindex])π ENDπ END;π π PROCEDURE dividebyn;ππ { This procedure is needed to get FFT to scale correctly. }π π VARπ index : dataindextype;π π BEGIN { dividebyn }π WITH data DOπ FOR index := 1 TO complexpoints DOπ WITH cp[index] DOπ BEGINπ realpart := realpart/complexpoints;π imagpart := imagpart/complexpointsππ ENDπ END;π π BEGIN { forwardfft }π docomplextransform;π shufflecoefficients;π dividebynπ END;π π { Note that the data slots and coefficient slots in the mixedπ data type share storage. From the first complex coefficient,π we can derive the DC and noise term; from pairs of the remainingπ coefficients, we can derive pairs of sine/cosine terms. }π π π BEGIN { fftofreal }π forwardfft (mixed.dataslot, realpoints DIV 2);π temp1 := mixed.dataslot.cp[1];π WITH mixed.coefslot, temp1 DOπ BEGINπ dcterm := (realpart + imagpart)/2;π noiseterm := (realpart - imagpart)/2π END;π baseangle := -twopi/realpoints;π FOR index := 1 TO realpoints DIV 4 DOπ BEGINπ minusindex := (realpoints DIV 2) - index;π WITH mixed.dataslot DOπ BEGINπ conjugate (cp[succ(minusindex)], temp2);π cadd (cp[succ(index)], temp2, temp1);π csubtract (cp[succ(index)], temp2, temp2)π END;π w.realpart := sin(index*baseangle);π w.imagpart := -cos(index*baseangle);π cmultiply (w, temp2, temp2);π cadd (temp1, temp2, temp3);π csubtract (temp1, temp2, temp2);π conjugate (temp2, temp2);π WITH mixed.coefslot.freqterms[index], temp3 DOπ BEGINπ cosineterm := realpart/2;π sineterm := -imagpart/2π END;π WITH mixed.coefslot.freqterms[minusindex], temp2 DOπ BEGINπ cosineterm := realpart/2;π sineterm := imagpart/2π ENDπ ENDπ END;π π FUNCTION omegat (f : freqindextype; t : dataindextype) : real;π π { computes omega*t for particular harmonic, index }ππ BEGIN { omegat }π omegat := twopi * f * pred(t) / maxarraysizeπ END;π π { main test routine starts here }π π BEGINπ WITH mixed.dataslot DOπ FOR didx := 1 TO maxarraysize DOπ rp[didx] := (23π + 13 * sin(omegat (7, didx))π + 28 * cos(omegat (22, didx)));π fftofreal (mixed, maxarraysize);π WITH mixed.coefslot DOπ writeln ('DC = ', dcterm:10:2, ' ':5, 'Noise = ', noiseterm:10:2);π FOR fidx := 1 TO maxfreqsize DOπ BEGINπ WITH mixed.coefslot.freqterms[fidx] DOπ write (fidx:4, round(cosineterm):4, round(sineterm):4, ' ':4);π IF fidx MOD 4 = 0π THEN writelnπ END;π writeln;π writeln ('The expected result should have been:');π writeln (' DC = 23, noise = 0, ');π writeln (' sine 7th harmonic = 13, cosine 22nd harmonic = 28')π END.π 6 08-25-9409:08ALL MARCEL HOOGEVEEN FFT algorithm SWAG9408 +╥╕ 19 ₧ {πFrom: marcel.hoogeveen@hacom.wlink.nl (Marcel Hoogeveen)ππGR> FFT stands for Fast Fourier Transform. It is a quick way to converπGR> time domain data (ie oscilliscopy data with time on the x-axis) toπGR> frequency domain (frequency on the x-axis, like a frequency spectrumπGR> analyzer). This is a usefull data analysis method. I would also likeπGR> to get some source for this.πππThis is what i have of FFT source code, it should work if you tweak it a bit.π(It did for me when i used it in my analasis program).πDon't ask me how it works, i know how a DFT works but a FFT well .. just useπthe source. :)ππ}πProgram FFT;πConst Twopi=6.283185303;ππType Curve=array[1..nfft] of real;ππVar {This is for you to find out}ππ{ Calculation of the Discrete Fourier Transfor }π{ Using a Fast Fourier Transform algorithm }π{ }π{ XR and XI are array of reals !!! }π{ They contain on entry the input sequence and }π{ on return the transfrom }π{ ISI defines the transform direction }π{ If ISI=-1 then forward, if ISI=1 then invert }π{ }π{ The dimension is 2**M }ππProcedure RFFT (VAR XR,XI:Curve; N:integer; ISI:Integer);πVarπM,NV2,LE,LE1,IP,I,J,K,L: Integer;πC,THETA,UR,UI,TR,TI:Real;ππBeginπM:=Round(LN(N)/LN(2));πNV2:= N DIV 2;πJ:=1;πFor I:= 1 to N-1 doπBeginπIf (I<J) thenπBeginπTR:=XR[J]; TI:=X[J];πXR[J]:=XR[I]; XI[J]:=XI[I];πXR[I]:=TR; XI[I]:=TI;πEnd;πK:=NV2;πWhile (K<J) doπBeginπJ:=J-K;πK:=K DIV 2;πEnd;πJ:=J+K;πEnd;πLE:=1;πC:=ISI*TWOPI;πFor L:=1 TO M doπBeginπLE1:=LE;πLE:=LE*2;πFor J:=1 TO LE1 doπBeginπTHETA:= C*(J-1)/LE;πUR:=COS(tHETA);πUI:=SIN(THETA);πI:=J;πRepeatπIP:=I+LE1;πTR:=XR[IP]*UR-XI[IP]*UI;πTI:+XR[IP]*UI+XI[IP]*UR;πXR[IP]:=XR[I]-TR; XI[IP]:=XI[I]-TP;πXR[I]:=XR[I]+TR; XI[I]:=XI[I]+TI;πI:=I+LE;πUntil (I>=N)πEnd;πEnd;πIf ISI=-1 thenπBeginπFor I:= 1 TO N doπBeginπXR[I]:=4*XR[I]/N; XI[I]:=4*XI[I]/N;πEnd;πEnd;πEnd;πππBeginπFor I := 1 to NUMSAM doπBeginπFREAL[I]:=SAMPLEBUFFER[I];πFIMAG[I]:=0;πEnd;πRFFT(FREAL,FIMAG,NUMSAM,-1);πDC:=FREAL[1]/2;πFor I:= 1 to NUMSAM dOπFREAL[I]:=FREAL[I]*FREAL[I]+fIMAG[I]*FIMAG[I];πEnd.π 7 08-25-9409:08ALL RANDALL ELTON DING Random Gaussian VariablesSWAG9408 òe┼ 24 ₧ (*πFrom: randyd@alpha2.csd.uwm.edu (Randall Elton Ding)ππ>I a program I'm currently struggeling with, I need to get a random numberπ>from a Gaussian distribution. Anybody got any ideas or anybody able to pointπ>to something which does the job.ππThis does a pretty good job of generating a gaussian random variableπwith mean `a` and standard deviation `d`.πThis program also does a graphic plot to demonstrate the function.ππFirst, here is the origional C source if the gaussian functionπwhich I transcribed to beloved pascal..ππ/* ------------------------------------------------ *π * gaussian -- generates a gaussian random variable *π * with mean a and standard deviation d *π * ------------------------------------------------ */π double gaussian(a,d)π double a,d;π {π static double t = 0.0;π double x,v1,v2,r;π if (t == 0) {π do {π v1 = 2.0 * rnd() - 1.0;π v2 = 2.0 * rnd() - 1.0;π r = v1 * v1 + v2 * v2;π } while (r>=1.0);π r = sqrt((-2.0*log(r))/r);π t = v2*r;π return(a+v1*r*d);π }π else {π x = t;π t = 0.0;π return(a+x*d);π }π }πππ* ----------------------------------------------------------------------π* now, the same thing in pascalπ* ----------------------------------------------------------------------π*)ππ{$N+}πprogram testgaussian;ππuses graph,crt;ππconstπ bgipath = 'e:\bp\bgi';ππprocedure initbgi;π varπ errcode,grdriver,grmode: integer;ππ beginπ grdriver:= detect;π grmode:= 0;π initgraph (grdriver,grmode,bgipath);π errcode:= graphresult;π if errcode <> grok then beginπ writeln ('Graphics error: ',grapherrormsg (errcode));π halt (1);π end;π end;ππππfunction rnd: double; { this isn't the best, but it works }π var { returns a random number between 0 and 1 }π i: integer;π r: double;ππ beginπ r:= 0;π for i:= 1 to 15 do beginπ r:= r + random(10);π r:= r/10;π end;π rnd:= r;π end;ππππfunction gaussian(a,d: double): double; { a is mean }π const { d is standard deviation }π t: double = 0; { pascal's equivalent to C's static variable }ππ varπ x,v1,v2,r: double;ππ beginπ if t=0 then beginπ repeatπ v1:= 2*rnd-1;π v2:= 2*rnd-1;π r:= v1*v1+v2*v2π until r<1;π r:= sqrt((-2*ln(r))/r);π t:= v2*r;π gaussian:= a+v1*r*d;π endπ else beginπ x:= t;π t:= 0;π gaussian:= a+x*d;π end;π end;ππππprocedure testplot;π varπ x,mx,my,y1: word;π y: array[1..999] of word;π { ^^^ make this bigger if you have incredible graphics }π beginπ initbgi;π mx:= getmaxx+1;π my:= getmaxy;π fillchar(y,sizeof(y),#0);π repeatπ x:= trunc(gaussian(mx/2,50));π y1:= y[x];π putpixel(x,my-y1,white);π y[x]:= y1+1;π until keypressed;π closegraph;π end;ππππbeginπ randomize;π testplot;πend.ππ 8 08-25-9409:09ALL MARTIN PREISHUBER Math Unit SWAG9408 ─u2╙ 487 ₧ {πFrom: Martin Preishuber <martin_p@efn.efn.org>ππmycalc.pas that is a unit with mathematical function. the numbersπ are based on 65536, so you can calculate with reallyπ huge numbers.πrabin.pas it's a demo program for mycalc. you can test largeπ number,s whether it is a prime or notππboth programs are documented in german, so i guess that documentationπwon't help much :-(π}ππ(* ----------------------------------------------------------------------- *)π(* RabinTest prüft, ob eine Zahl eine Primzahl ist *)π(* ----------------------------------------------------------------------- *)ππ{$M 65000, 0, 655360} (* Stack auf maximale Größe *)ππPROGRAM RabinTest;ππUSES Crt, (* Ein/Ausgabefunktionen *)π Extend, (* erweiterte I/O - Funktionen *)π MyCalc; (* Funktionen für das Rechnen mit großen Zahlen *)ππ(* ----------------------------------------------------------------------- *)ππFUNCTION Expt(zahl : Real; hoch : INTEGER) : Real;π (* Berechnung des Exponenten einer Realzahl (einfach, weil nur für die *)π (* Berechnung von AnzahlTests nötig *)πVAR i : INTEGER; (* Zählvariable *)π hilfe : Real; (* Hilfsvariable für das Ergebnis *)πBEGINπ IF hoch = 0 THEN (* Hochzahl = 0 *)π Expt := 1 (* => Ergebnis = 1 *)π ELSEπ BEGINπ hilfe := 1; (* Ergebnis mit 1 initialisieren *)π FOR i := 1 TO hoch DO hilfe := hilfe * zahl;π (* Zahl hoch mal mit sich selbst multiplizieren *)π Expt := hilfe; (* Ergebnis zurückliefern *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)ππFUNCTION AnzahlTests(wahrscheinlichkeit : Real) : INTEGER;π (* ermittelt die Anzahl Tests, welche nötig sind um die gewünschte *)π (* Wahrscheinlichkeit zu erreichen *)πVAR anzahl : INTEGER; (* Anzahl der nötigen Tests *)πBEGINπ anzahl := 0; (* Anzahl mit 0 initialisieren *)π REPEATπ INC(anzahl); (* Anzahl um 1 erhöhen *)π UNTIL ((1/(Expt(4,anzahl))) < wahrscheinlichkeit);π (* solange wiederholen, bis W > (1/4)^x *)π AnzahlTests := anzahl; (* Anzahl Tests zurückgeben *)πEND;ππ(* ----------------------------------------------------------------------- *)ππFUNCTION EvenString(zahl : STRING) : BOOLEAN;π (* prüft, on ein String gerade ist *)πBEGINπ EvenString := NOT Odd(Ord(zahl[Length(zahl)]) - 48);πEND; (* prüft, ob die letzte Stelle des Strings gerade ist *)ππ(* ----------------------------------------------------------------------- *)ππFUNCTION Div5(zahl : STRING) : BOOLEAN;π (* prüft, ob ein String durch 5 dividierbar ist *)πVAR last : BYTE; (* letzte Stelle von zahl *)πBEGINπ last := Ord(zahl[Length(zahl)]) - 48; (* letzte Stelle ermitteln *)π IF (last = 0) OR (last = 5) THEN (* Falls letzte Stelle 0 oder 5 ist *)π Div5 := TRUE (* ist die Zahl durch 5 dividierbar *)π ELSEπ Div5 := FALSE; (* sonst nicht *)πEND; (* prüft, ob die letzte Stelle des Strings gerade ist *)ππ(* ----------------------------------------------------------------------- *)ππFUNCTION Div3(zahl : STRING) : BOOLEAN;π (* prüft, ob ein String durch 5 dividierbar ist *)πVAR ziffernSumme : WORD; (* Ziffernsumme des Strings *)π laenge : BYTE; (* Laenge des Strings *)π i : BYTE; (* Zählvariable *)πBEGINπ ziffernSumme := 0; (* Ziffernsumme initialisieren *)π laenge := Length(zahl); (* Länge des Strings ermitteln *)π FOR i := 1 TO laenge DO (* ZiffernSumme ermitteln *)π BEGINπ ziffernSumme := ziffernSumme + (Ord(zahl[i]) - 48);π (* aktuelle Zahl zur Ziffernsumme addieren *)π END;π IF (ZiffernSumme MOD 3) = 0 THEN (* Ziffernsumme durch 3 teilbar *)π Div3 := TRUE (* => Zahl durch 3 teilbar *)π ELSEπ Div3 := FALSE; (* sonst ist Zahl nicht durch 3 teilbar *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* Bedingung 1 beim Rabintest: b^v≡1 mod p *)ππFUNCTION Bedingung1(b, v, p, pMinus1, EINS : CalcStr) : BOOLEAN;πVAR hilfe : CalcStr; (* HilfsCalcString *)πBEGINπ ExptModCalcStr(b, v, p, hilfe); (* b^v mod p berechnen *)ππ Write('b^v mod p = '); PrintCalcStr(hilfe);ππ IF EqualCalcStr(hilfe, EINS) THEN (* Falls Ergebnis = 1 *)π Bedingung1 := TRUE (* Bedingung 1 erfüllt *)π ELSEπ IF EqualCalcStr(hilfe, pMinus1) THENπ Bedingung1 := TRUE (* Bedingung 2 mit r=0 erfüllt *)π ELSEπ Bedingung1 := FALSE; (* sonst ist Bedingung 1 nicht erfüllt *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* Bedingung 2 beim Rabintest: b^(v^(2r)) ≡ -1 mod p *)ππFUNCTION Bedingung2(VAR b, v, u, p, pMinus1, EINS : CalcStr) : BOOLEAN;πVAR r : CalcStr; (* zu durchlaufende Hochzahlen *)π ZWEI : CalcStr; (* konstante CalcString-Darstellung für 2 *)π hilfe1 : CalcStr; (* HilfsCalcString *)π hilfe2 : CalcStr; (* HilfsCalcString *)πBEGINπ InitCalcStr(r); (* r initialisieren *)π r.stellen := 1; (* r hat 1 Stelle, diese ist zu Beginn 0 *)π r.zahl[1] := 1; (* r läuft von 1 weg, weil Bedingung mit r=0 schon in *)π (* Bedingung 1 geprüft wird *)π WordToCalcStr(2, ZWEI); (* Zahl zwei in CalcString ermitteln *)π WHILE LessCalcStr(r, u) DO (* solange r < u *)π BEGINππ Write('r = '); PrintCalcStr(r);ππ ExptCalcStr(ZWEI, r, hilfe1); (* 2^r ermitteln *)π MulCalcStr(hilfe1, v, hilfe2); (* 2^r mit v multiplizieren *)π ExptModCalcStr(b, hilfe2, p, hilfe1); (* b^(v2^r) MOD p berechnen *)ππ Write('b^(v2^r) mod p = '); PrintCalcStr(hilfe1);ππ IF EqualCalcStr(hilfe1, pMinus1) THEN (* Falls Ergebnis = -1 *)π BEGINπ Bedingung2 := TRUE; (* Bedingung 2 erfüllt *)π EXIT;π END;π AddCalcStr(r, EINS, hilfe2); (* r um 1 erhöhen *)π r := hilfe2; (* r wieder zuweisen *)π END;π Bedingung2 := FALSE; (* 2. Bedingung nicht erfüllt *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* Rabin prüft eine Zahl mit Hilfe des RabinTests *)ππFUNCTION Rabin(primzahl : STRING; anzahl : INTEGER) : BOOLEAN;πVAR p : CalcStr; (* zu untersuchende Primzahl *)π pMinus1 : CalcStr; (* Primzahl - 1 *)π EINS : CalcStr; (* konstanter Wert für 1 *)π u : CalcStr; (* p-1 = 2^u*v (v ungerade) *)π v : CalcStr; (* p-1 = 2^u*v (v ungerade) *)π b : CalcStr; (* Basis bei Primzahltest *)π hilfe : CalcStr; (* HilfsCalcString *)π i : BYTE; (* Zählvariable *)πBEGINπ StrToCalcStr(primzahl, p); (* Primzahl ins 65536-System umwandeln *)π WordToCalcStr(1, EINS); (* CalcStringdarstellung von 1 *)π SubCalcStr(p, EINS, pMinus1); (* vom pMinus1 = p - 1 *)π InitCalcStr(u); (* u initialisieren *)π u.stellen := 1; (* u besitzt 1 Stellen, diese ist 0 *)π v := pMinus1; (* v ist zu Beginn p-1 *)π REPEATπ AddCalcStr(u, EINS, hilfe); (* 2^u, Potenz um 1 erhöhen *)π u := hilfe; (* und wieder u zuweisen *)π Div2CalcStr(v); (* v durch 2 dividieren *)π UNTIL OddCalcStr(v); (* solange, bis v ungerade ist *)ππ Write('p = '); PrintCalcStr(p);π Write('u = '); PrintCalcStr(u);π Write('v = '); PrintCalcStr(v);ππ FOR i := 1 TO anzahl DO (* Anzahl Tests durchführen *)π BEGINπ RandomCalcStr(p, b); (* zufällige Basis ermitteln *)ππ Write('b = '); PrintCalcStr(b);ππ IF (Bedingung1(b, v, p, pMinus1, EINS) = FALSE) THENπ (* 1. Bedingung prüfen *)π IF (Bedingung2(b, v, u, p, pMinus1, EINS) = FALSE) THENπ BEGIN (* 2. Bedingung prüfen *)π Rabin := FALSE;π EXIT; (* beide Bedingungen nicht erfüllt => keine Primzahl *)π END;π END;π Rabin := TRUE; (* Rabintest bestanden *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* PrimeTest prüft, ob Zahl eine Primzahl ist *)ππFUNCTION PrimeTest(zahl : STRING; anzahlTests : INTEGER; VAR meldung : STRING)π: BOOLEAN;πBEGINπ IF EvenString(zahl) THEN (* Zahl ist durch 2 dividierbar *)π BEGINπ PrimeTest := FALSE; (* => keine Primzahl *)π meldung := 'gerade Zahl'; (* Meldung zurückgeben *)π ENDπ ELSEπ IF Div5(zahl) THEN (* Falls Zahl durch 5 dividierbar ist *)π BEGINπ PrimeTest := FALSE; (* => keine Primzahlπ*)π meldung := 'Zahl durch 5 dividierbar'; (* Meldung zurückgeben *)π ENDπ ELSEπ IF Div3(zahl) THEN (* Zahl durch 3 dividierbar *)π BEGINπ PrimeTest := FALSE; (* => keine Primzahl *)π meldung := 'Zahl durch 3 dividierbar'; (* Meldung zurückgeben *)π ENDπ ELSEπ BEGINπ IF NOT Rabin(zahl, anzahlTests) THEN (* Falls Rabintest negativ *)π BEGINπ PrimeTest := FALSE; (* keine Primzahl *)π meldung := 'Rabintest'; (* Meldung zurückgeben *)π ENDπ ELSEπ PrimeTest := TRUE; (* sonst ist Zahl Primzahl *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* Hauptprogramm erledigt die Ein/Ausgabe *)ππPROCEDURE Hauptprogramm; (* Hauptprogramm des Primzahltests *)πVAR anzahl : INTEGER; (* Anzahl notwendiger Tests *)π wahrscheinlichkeit : Real; (* Fehlerwahrscheinlichkeit *)π primzahl : STRING; (* zu untersuchende Zahl *)π meldung : STRING; (* Meldung, warum keine Primzahl *)π prim : BOOLEAN; (* ist sie Primzahl oder nicht *)πBEGINπ ClrScr; (* Bildschirm löschen *)π Frame(27, 1, 53, 3, 1, '', TRUE); (* Rahmen ausgeben *)π WriteXY(29, 2, 'Primzahltest nach Rabin');π GotoXY(1, 6);π WriteLn('1. Test: gerade Zahl'); (* Tests anzeigen *)π WriteLn('2. Test: Zahl durch 5 dividierbar');π WriteLn('3. Test: Ziffernsumme durch 3 dividerbar');π WriteLn('4. Test: RabinTest');π WriteLn;π Write('Primzahl (p): '); ReadLn(primzahl); (* Primzahl eingeben *)π Write('Fehlerwahrscheinlichkeit: '); ReadLn(wahrscheinlichkeit);π (* Fehlerwahrscheinlichkeit eingeben *)π anzahl := AnzahlTests(wahrscheinlichkeit); (* Testanzahl ermitteln *)π WriteLn;π WriteLn('Anzahl Tests: ', anzahl);π WriteLn;π prim := PrimeTest(primzahl, anzahl, meldung); (* auf Primzahl testen *)π Write(primzahl, ' ist ');π IF NOT prim THENπ WriteLn('keine Primzahl (',meldung,')') (* Meldung ausgeben *)π ELSEπ WriteLn('Primzahl');πEND;ππ(* ----------------------------------------------------------------------- *)ππBEGINπ Hauptprogramm; (* Hauptprogramm aufrufen *)πEND.ππ(* ----------------------------------------------------------------------- *)ππ(* ----------------------------------------------------------------------- *)π(* MyCalc stellt eine LongInteger-Arithmetik zur Verfuegung *)π(* ----------------------------------------------------------------------- *)ππ{$M 65000, 0, 655360} (* Stack auf maximale Groesse *)ππUNIT MyCalc;ππINTERFACEππCONST MAXCALCSTR = 500; (* maximal 500 Word-Zahlen *)ππTYPE CalcStr = RECORDπ stellen : WORD; (* Anzahl der belegten Stellen *)π zahl : ARRAY[1..MAXCALCSTR] OF WORD; (* große Zahl *)π END;ππPROCEDURE InitCalcStr(VAR calcZahl : CalcStr);πPROCEDURE ReverseCalcStr(VAR ergebnis : CalcStr);πPROCEDURE SwapCalcStr(VAR zahl1, zahl2 : CalcStr);πPROCEDURE PrintCalcStr(VAR calcZahl : CalcStr);πPROCEDURE StrToCalcStr(zeichenkette : STRING; VAR ergebnis : CalcStr);πPROCEDURE WordToCalcStr(zahl : WORD; VAR ergebnis : CalcStr);πPROCEDURE AddCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πPROCEDURE SubCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πPROCEDURE Mul2CalcStr(VAR calcZahl : CalcStr);πPROCEDURE Div2CalcStr(VAR calcZahl : CalcStr);πPROCEDURE MulCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πPROCEDURE ExptCalcStr(VAR basis, exponent: CalcStr; VAR ergebnis : CalcStr);πPROCEDURE RandomCalcStr(VAR calcZahl: CalcStr; VAR ergebnis : CalcStr);πPROCEDURE MulModCalcStr(VAR zahl1, zahl2, modul : CalcStr; VAR ergebnis :πCalcStr);πPROCEDURE ExptModCalcStr(VAR basis, exponent, modul : CalcStr; VAR ergebnis :πCalcStr);ππFUNCTION CalcStrLength(VAR calcZahl : CalcStr) : WORD;πFUNCTION CalcStrToStr(VAR calcZahl : CalcStr; VAR ergebnis : STRING) : BOOLEAN;πFUNCTION CalcStrToWord(VAR calcZahl : CalcStr; VAR ergebnis : WORD) : BOOLEAN;πFUNCTION EqualCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πFUNCTION GreaterCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πFUNCTION GreaterEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πFUNCTION LessCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πFUNCTION LessEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πFUNCTION EvenCalcStr(VAR calcZahl : CalcStr) : BOOLEAN;πFUNCTION OddCalcStr(VAR calcZahl : CalcStr) : BOOLEAN;πFUNCTION DivCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) :πBOOLEAN;πFUNCTION ModCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) :πBOOLEAN;ππIMPLEMENTATIONππUSES Crt; (* Ein/Ausgabefunktionen *)ππVAR EMPTYCALCSTR : CalcStr; (* leerer CalcString *)π i : WORD;π (* Zählvariable zur Initialisierung von EMPTYCALCSTR *)ππ(* ======================================================================= *)π(* Bitmanipulationen *)ππ(* ----------------------------------------------------------------------- *)π(* SetBit setzt das BitNr.te Bit in Zahl *)ππFUNCTION SetBit(zahl : WORD; bitNr : BYTE): WORD;πBEGINπ SetBit := zahl OR (1 SHL bitNr)π (* BitNr Stellen nach links shiften und mit oder verknüpfen *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* TestBit prüft, ob das BitNr.te Bit in Zahl gesetzt ist *)ππFUNCTION TestBit(zahl : WORD; bitNr: BYTE): BOOLEAN;πBEGINπ TestBit := (((zahl SHR bitNr) AND 1) = 1)π (* Bit ist dann gesetzt, falls an der BitNr. Stelle bei einer *)π (* Und-Verknüpfung wieder 1 das Ergebnis ist *)πEND;ππ(* ======================================================================= *)π(* Hilfsfunktionen für Strings *)ππ(* ----------------------------------------------------------------------- *)π(* TestString prüft, ob im String eine gültige Zahl enthalten ist *)ππFUNCTION TestString(zeichenkette : STRING) : BOOLEAN;πVAR laenge : BYTE; (* Länge der Zeichenkette *)π i : BYTE; (* Zählvariable *)πBEGINπ laenge := Length(zeichenkette); (* Länge der Zeichenkette ermitteln *)π FOR i := 1 TO laenge DOπ IF (NOT (zeichenkette[i] IN ['0'..'9'])) THEN (* keine Zahl *)π BEGINπ TestString := FALSE; (* String ist ungültig *)π EXIT; (* Funktion verlassen *)π END;π TestString := TRUE;πEND;ππ(* ----------------------------------------------------------------------- *)π(* OddString prüft, ob ein String ungerade ist *)ππFUNCTION OddString(zeichenkette : STRING) : BOOLEAN;πVAR zahl : BYTE; (* Bytedarstellung von Zeichen *)π dummy : INTEGER; (* dient zur Überprüfung von zeichen bei Umwandlung *)π last : CHAR; (* letztes Zeichen in zeichenkette *)π laenge : BYTE; (* Länge der Zeichenkette *)πBEGINπ laenge := Length(zeichenkette); (* Länge muß neu ermittelt werden *)π last := zeichenkette[laenge]; (* letztes Zeichen *)π Val(last, zahl, dummy); (* letztes Zeichen in zahl umwandeln *)π oddString := Odd(zahl); (* prüfen, ob zahl ungerade ist *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* StrDiv2 dividiert einen String durch 2 *)ππFUNCTION StrDiv2(zeichenkette : STRING) : STRING;πVAR hilfe : STRING; (* Hilfsstring für das Ergebnis *)π index : BYTE; (* Index für Position in zeichenkette *)π laenge : BYTE; (* Länge der Zeichenkette *)π zahl : BYTE; (* zu dividierender Faktor *)π zeichen : CHAR; (* Zeichendarstellung von Zahl *)π dummy : INTEGER;π (* dient zur Überprüfung von zeichen bei Umwandlung *)π uebertrag : BOOLEAN; (* ist ein Übertrag aufgetreten *)πBEGINπ hilfe := ''; (* hilfe initialisieren *)π laenge := Length(zeichenkette); (* Länge der zeichenkette *)π IF oddString(zeichenkette) THEN (* falls die Zahl ungerade ist *)π DEC(zeichenkette[laenge]); (* Zahl um 1 dekrementieren *)π uebertrag := FALSE; (* kein Übertrag *)π IF zeichenkette[1] = '1' THEN (* falls an 1.Stelle ein 1er *)π BEGINπ index := 2; (* an 2.Stelle weitermachen *)π zahl := 10; (* Übertrag an 1.Stelle => zahl = 10 *)π ENDπ ELSEπ BEGINπ index := 1; (* beginne bei 1.Stelle *)π zahl := 0; (* => zahl = 0 *)π END;π REPEATπ zahl := zahl + Ord(zeichenkette[index]) - 48; (* Zahl ermitteln *)π IF (zahl AND 1) = 1 THEN uebertrag := TRUE;π (* ungerade zahl => Übertrag *)π zahl := zahl SHR 1; (* zahl durch 2 dividieren *)π zeichen := Chr(zahl + 48); (* Zahl wieder in ASCII-Zeichen umwandeln *)π hilfe := hilfe + zeichen; (* und an hilfe anhängen *)π INC(index); (* Index um 1 erhöhen *)π IF uebertrag THEN (* Übertrag *)π zahl := 10 (* Übertrag in zahl sichern *)π ELSEπ zahl := 0; (* sonst zahl = 0 *)π uebertrag := FALSE; (* Annahme: kein Übertrag *)π UNTIL index > laenge; (* keine Zeichen mehr zum dividieren *)π StrDiv2 := hilfe; (* Ergebnis steht in Hilfe *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* StrMul2 multipliziert einen String mit 2 *)ππFUNCTION StrMul2(zeichenkette : STRING) : STRING;πVAR laenge : BYTE; (* Laenge der zeichenkette *)π i : BYTE; (* Zählvariable *)π hilfe : STRING; (* Hilfsstring für Ergebnis *)π dummyStr : STRING; (* dient zur Umwandlung Zahl -> Zeichen *)π uebertrag : BOOLEAN; (* Übertrag ja/nein *)π zeichen : CHAR; (* aktuelles Zeichen *)π zahl : BYTE; (* Byte-Darstellung von zeichen *)π dummy : INTEGER; (* dient zur Prüfung von zeichen bei Umwandlung *)πBEGINπ laenge := Length(zeichenkette); (* Länge ermitteln *)π uebertrag := FALSE; (* Annahme: kein Übertrag *)π hilfe := ''; (* Hilfsstring initialisieren *)π FOR i := laenge DOWNTO 1 DO (* zeichenkette rückwärts durchlaufen *)π BEGINπ zeichen := zeichenkette[i]; (* aktuelles Zeichen ermitteln *)π zahl := Ord(zeichen) - 48; (* in eine Zahl umwandeln *)π zahl := zahl SHL 1; (* Zahl mit 2 multiplizieren *)π IF uebertrag THEN INC(zahl); (* bei Übertrag 1 addieren *)π IF (zahl >= 10) THEN (* falls Zahl >= 10 *)π BEGINπ uebertrag := TRUE; (* Übertrag aufgetreten *)π zahl := zahl - 10; (* Übertrag wegschneiden *)π ENDπ ELSEπ uebertrag := FALSE; (* sonst kein Übertrag *)π zeichen := Chr(zahl + 48); (* zahl in Zeichen umwandeln *)π hilfe := zeichen + hilfe; (* und an Hilfe anhängen *)π END;π IF uebertrag THEN hilfe := '1' + hilfe;π (* restlichen Übertrag noch berücksichtigen *)π StrMul2 := hilfe; (* Ergebnis zuweisen *)πEND;ππ(* ======================================================================= *)π(* Operationen auf den Datentyp CalcString *)ππ(* ----------------------------------------------------------------------- *)π(* InitCalcStr initialisiert einen CalcString: *)ππPROCEDURE InitCalcStr(VAR calcZahl : CalcStr);πBEGINπ calcZahl := EMPTYCALCSTR; (* leeren CalcStr zuweisen *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* CalcStrLength liefert die Länge des CalcStrings zurück *)ππFUNCTION CalcStrLength(VAR calcZahl : CalcStr) : WORD;πBEGINπ CalcStrLength := calcZahl.stellen; (* Länge ist in stellen gespeichert *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* ReverseCalcStr dreht einen CalcString um *)ππPROCEDURE ReverseCalcStr(VAR ergebnis : CalcStr);πVAR laenge : WORD; (* Anzahl Stellen im CalcString *)π i : WORD; (* Zählvariable *)π anzahl : WORD; (* benötigte Schrittzahl *)π hilfe : WORD; (* Zwischenspeicher *)πBEGINπ laenge := CalcStrLength(ergebnis); (* Länge des CalcStrings ermitteln *)π anzahl := laenge DIV 2; (* man benötigt nur laenge/2 Schritte *)π WITH ergebnis DO (* Record abarbeiten *)π BEGINπ FOR i := 1 TO anzahl DOπ BEGINπ hilfe := zahl[i]; (* i. Zahl merken *)π zahl[i] := zahl[laenge - (i - 1)];π (* i. Zahl wird zur entsprechenden Zahl von hinten *)π zahl[laenge - (i - 1)] := hilfe; (* hintere Zahl wird i.te Zahl *)π END;π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* SwapCalcStr vertauscht zwei CalcStrings *)ππPROCEDURE SwapCalcStr(VAR zahl1, zahl2 : CalcStr);πVAR hilfe : CalcStr; (* HilfsString für Vertauschung *)πBEGINπ hilfe := zahl1; (* Hilfe auf Zahl1 setzen *)π zahl1 := zahl2; (* Zahl1 auf Zahl2 setzen *)π zahl2 := hilfe; (* Zahl2 auf Hilfe setzen *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* PrintCalcStr gibt einen CalcString als Vektor auf dem Bildschirm aus *)ππPROCEDURE PrintCalcStr(VAR calcZahl : CalcStr);πVAR i : WORD; (* Zählvariable *)πBEGINπ ReverseCalcStr(calcZahl); (* calcZahl muß umgedreht werden *)π WITH calcZahl DO (* Recordtyp als Grundlage *)π BEGINπ IF stellen > 0 THEN (* Zahl darf nicht 0 sein *)π BEGINπ Write('('); (* positives Vorzeichen *)π FOR i := 1 TO (stellen - 1) DO (* alle Stellen abarbeiten *)π BEGINπ Write(zahl[i]); (* Zahl ausgeben *)π Write(','); (* durch Beistrich trennen *)π END;π Write(zahl[stellen]); (* letzte Zahl ausgeben *)π WriteLn(')'); (* Klammer des Vektors schließen *)π ENDπ ELSEπ WriteLn('(0)'); (* sonst 0 ausgeben *)π END;π ReverseCalcStr(calcZahl); (* calcZahl muß wieder umgedreht werden *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* StrToCalcStr wandelt einen String in einen CalcString um *)ππPROCEDURE StrToCalcStr(zeichenkette : STRING; VAR ergebnis : CalcStr);πVAR index : WORD; (* Index im ErgebnisCalcString *)π bitnr : BYTE; (* Nummer des zu setzenden Bit's *)π laenge : BYTE; (* Länge der Zeichenkette *)πBEGINπ ergebnis := EMPTYCALCSTR; (* ErgebnisString initialisieren *)π index := 1; (* erstes Element im CalcString *)π ergebnis.stellen := 1; (* Länge des CalcStrings wird auf 1 gesetzt *)π bitnr := 0; (* zu Beginn wird Bit 0 gesetzt/nicht gesetzt *)π laenge := Length(zeichenkette); (* Länge der Zeichenkette ermitteln *)π IF TestString(zeichenkette) THEN (* ist zeichenkette eine gültige Zahl *)π WITH ergebnis DO (* Record als Grundlage *)π BEGINπ REPEATπ IF oddString(zeichenkette) THEN (* ist zeichenkette ungerade ? *)π zahl[index] := SetBit(zahl[index], bitnr); (* Bit setzen *)π zeichenkette := StrDiv2(zeichenkette); (* Zeichenkette / 2 *)π IF zeichenkette <> '0' THEN (* falls noch nicht fertig *)π BEGINπ INC(bitnr); (* BitNr um 1 erhöhen *)π IF bitnr >= 16 THEN (* falls 1 Word voll ist *)π BEGINπ bitnr := 0; (* BitNr wird wieder 0 *)π INC(index); (* ein Element im CalcString weiter *)π INC(stellen); (* Länge des CalcStrings wird um 1 erhöht *)π END;π END;π UNTIL zeichenkette = '0'; (* bis zeichenkette auf 0 reduziert *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* CalcStrToStr wandelt eine CalcString um, falls er sich als String *)π(* darstellen läßt *)ππFUNCTION CalcStrToStr(VAR calcZahl : CalcStr; VAR ergebnis : STRING) : BOOLEAN;πVAR i : WORD; (* Zählvariable *)π BitNr : BYTE; (* Nummer des aktuellen Bits *)π anzahl : WORD; (* Anzahl Stellen im CalcString *)π laenge : BYTE; (* Länge des Ergebnisstrings *)πBEGINπ IF calcZahl.Stellen > 50 THEN (* Stringlänge würde überschritten *)π CalcStrToStr := FALSE (* Stringüberlauf *)π ELSEπ BEGIN (* Zahl paßt in einen String *)π ergebnis := '0'; (* Ergebnisstring ist zu Beginn 0 *)π anzahl := CalcStrLength(calcZahl); (* Länge des CalcStrings *)π FOR i := anzahl DOWNTO 1 DOπ (* alle Element des CalcStrings durchlaufen *)π FOR BitNr := 15 DOWNTO 0 DO (* alle Bits prüfen *)π BEGINπ ergebnis := StrMul2(ergebnis); (* ErgebnisString mit 2 mult. *)π IF TestBit(calcZahl.zahl[i], BitNr) THENπ (* Ist das Bit gesetzt ? *)π BEGINπ laenge := Length(ergebnis); (* Länge ermitteln *)π INC(ergebnis[laenge]); (* letztes Zeichen um 1 erhöhen *)π END;π END;π CalcStrToStr := TRUE; (* Umwandlung geglückt *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* WordToCalcStr wandelt eine Wordzahl in einen CalcString um *)ππPROCEDURE WordToCalcStr(zahl : WORD; VAR ergebnis : CalcStr);πBEGINπ ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π ergebnis.stellen := 1; (* 1 Stelle wird belegt *)π ergebnis.zahl[1] := zahl; (* Zahl in CalcZahl sichern *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* CalcStrToWord wandelt einen CalcString in eine Wordzahl um *)ππFUNCTION CalcStrToWord(VAR calcZahl : CalcStr; VAR ergebnis : WORD) : BOOLEAN;πBEGINπ IF (calcZahl.Stellen > 1) THENπ (* Zahl mit mehr als 1 Stelle können nicht umgewandelt werden *)π CalcStrToWord := FALSE (* keine Umwandlung *)π ELSEπ BEGINπ ergebnis := calcZahl.zahl[1]; (* Ergebnis zurückgeben *)π CalcStrToWord := TRUE; (* Umwandlung geglückt *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* EqualCalcStr prüft, ob ein CalcStr1 = CalcStr2 *)ππFUNCTION EqualCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πVAR i : WORD; (* Zählvariable *)πBEGINπ IF (zahl1.stellen <> zahl2.stellen) THENπ EqualCalcStr := FALSE (* unterschiedliche Anzahl Stellen *)π ELSE (* Stellenzahl gleich *)π BEGINπ FOR i := 1 TO zahl1.stellen DO (* alle Stellen abarbeiten *)π IF zahl1.zahl[i] <> zahl2.zahl[i] THEN (* Zahlen verschieden *)π BEGINπ EqualCalcStr := FALSE; (* Zahlen sind verschieden *)π EXIT; (* Schleife verlassen *)π END;π EqualCalcStr := TRUE; (* Zahlen sind gleich *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* GreaterCalcStr prüft, ob ein CalcStr1 > CalcStr2 *)ππFUNCTION GreaterCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πVAR i : WORD; (* Zählvariable *)π hilfe : BOOLEAN; (* Hilfsvariable *)πBEGINπ IF (zahl1.stellen > zahl2.stellen) THEN (* Zahl1 besitzt mehr Stellen *)π GreaterCalcStr := TRUE (* => Zahl1 > Zahl2 *)π ELSEπ IF (zahl1.stellen < zahl2.stellen) THENπ (* Zahl1 besitzt weniger Stellen *)π GreaterCalcStr := FALSE (* => Zahl1 nicht > Zahl2 *)π ELSE (* Stellenzahl gleich *)π BEGINπ FOR i := zahl1.stellen DOWNTO 1 DO (* alle Stellen abarbeiten *)π IF zahl1.zahl[i] > zahl2.zahl[i] THENπ (* i.Stelle von Zahl1 > i.te Stelle von Zahl2 *)π BEGINπ GreaterCalcStr := TRUE; (* Zahl1 > Zahl2 *)π EXIT; (* Schleife verlassen *)π ENDπ ELSEπ IF zahl1.zahl[i] < zahl2.zahl[i] THENπ (* i.Stelle von Zahl1 < i.te Stelle von Zahl2 *)π BEGINπ GreaterCalcStr := FALSE; (* Zahl1 nicht > Zahl2 *)π EXIT; (* Schleife verlassen *)π END;π GreaterCalcStr := FALSE; (* alle Stellen sind gleich *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* GreaterEqual prüft, ob Zahl1 >= Zahl2 *)ππFUNCTION GreaterEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πBEGINπ GreaterEqual := NOT LessCalcStr(zahl1, zahl2);π (* Zahl1 >= Zahl2, wenn Zahl1 nicht kleiner als Zahl2 ist *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* LessCalcStr prüft, on Zahl1 < Zahl2 *)ππFUNCTION LessCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πVAR i : WORD; (* Zählvariable *)π hilfe : BOOLEAN; (* Hilfsvariable *)πBEGINπ IF (zahl1.stellen < zahl2.stellen) THEN (* Zahl1 besitzt weniger Stellen *)π LessCalcStr := TRUE (* => Zahl1 < Zahl2 *)π ELSEπ IF (zahl1.stellen > zahl2.stellen) THEN (* Zahl1 besitzt mehr Stellen *)π LessCalcStr := FALSE (* => Zahl1 nicht < Zahl2 *)π ELSE (* Stellenzahl gleich *)π BEGINπ FOR i := zahl1.stellen DOWNTO 1 DO (* alle Stellen abarbeiten *)π IF zahl1.zahl[i] < zahl2.zahl[i] THENπ (* i.Stelle von Zahl1 < i.te Stelle von Zahl2 *)π BEGINπ LessCalcStr := TRUE; (* Zahl1 < Zahl2 *)π EXIT; (* Schleife verlassen *)π ENDπ ELSEπ IF zahl1.zahl[i] > zahl2.zahl[i] THENπ (* i.Stelle von Zahl1 > i.te Stelle von Zahl2 *)π BEGINπ LessCalcStr := FALSE; (* Zahl1 nicht < Zahl2 *)π EXIT; (* Schleife verlassen *)π END;π LessCalcStr := FALSE; (* alle Stellen sind gleich *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* LessEqual prüft, ob Zahl1 <= Zahl2 *)ππFUNCTION LessEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN;πBEGINπ LessEqual := NOT GreaterCalcStr(zahl1, zahl2);π (* Zahl1 <= Zahl2, wenn Zahl1 nicht größer als Zahl2 ist *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* EvenCalcStr prüft, ob ein CalcString gerade ist *)ππFUNCTION EvenCalcStr(VAR calcZahl : CalcStr) : BOOLEAN;πBEGINπ EvenCalcStr := NOT Odd(calcZahl.zahl[1]);π (* CalcZahl ist gerade, falls die letzte Stelle nicht ungerade ist *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* OddCalcStr prüft, ob ein CalcString ungerade ist *)ππFUNCTION OddCalcStr(VAR calcZahl : CalcStr) : BOOLEAN;πBEGINπ OddCalcStr := Odd(calcZahl.zahl[1]);π (* CalcZahl ist ungerade, falls die letzte Stelle ungerade ist *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* AddCalcStr addiert zwei CalcStrings *)ππPROCEDURE AddCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πVAR anzahl : WORD; (* Anzahl Stellen für Addition *)π i : WORD; (* Zählvariable *)π summe : LongInt; (* Hilfsvariable zur Prüfung eines Übertrags *)π ueberlauf : BYTE; (* Überlauf = 1, kein Überlauf = 0 *)π addition : BOOLEAN; (* können Zahlen addiert werden oder nicht *)πBEGINπ {$Q-} (* Überlaufprüfung ausschalten *)π ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π anzahl := zahl1.stellen; (* Annahme: Zahl 1 ist größer *)π IF zahl2.stellen > anzahl THEN (* Falls doch 2. Zahl größer ist *)π anzahl := zahl2.stellen; (* so viele Stellen müssen addiert werden *)π ueberlauf := 0; (* zu Beginn kein Überlauf *)π FOR i := 1 TO anzahl DO (* anzahl Stellen abarbeiten *)π BEGINπ ergebnis.zahl[i] := zahl1.zahl[i] + zahl2.zahl[i] + ueberlauf;π (* ergebnis ist die Summe der beiden Zahlen (kann einfach *)π (* addiert werden, weil Überlaufprüfung ausgeschaltet ist *)π summe := LongInt(zahl1.zahl[i]) + LongInt(zahl2.zahl[i]) + ueberlauf;π (* Summe ohne Überlauf *)π IF (summe > ergebnis.zahl[i]) THEN (* ist ein Überlauf aufgetreten *)π ueberlauf := 1 (* ja -> Überlauf auf 1 setzen *)π ELSEπ ueberlauf := 0; (* nein -> Überlauf ist 0 *)π END;π IF (ueberlauf = 1) THEN (* letzter Überlauf muß geprüft werden *)π BEGINπ ergebnis.stellen := anzahl + 1; (* letzter Überlauf belegt 1 Feld *)π ergebnis.zahl[anzahl + 1] := 1; (* Zahl 1 steht im letzten Feld *)π ENDπ ELSEπ ergebnis.stellen := anzahl;π (* gleich viele Stellen wie die längere Zahl *)π {$Q+} (* Überlaufprüfung wieder einschalten *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* SubCalcStr subtrahiert zahl2 von zahl1 *)ππPROCEDURE SubCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πVAR swapped : BOOLEAN; (* wurden Zahl1 und Zahl2 vertauscht ? *)π i : WORD; (* Zählvariable *)π uebertrag : BYTE; (* Übertrag: 1, kein Übertrag: 0 *)πBEGINπ ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π swapped := FALSE; (* Zahlen wurden nicht vertauscht *)π uebertrag := 0; (* kein Übertrag *)π IF GreaterCalcStr(zahl2, zahl1) THEN EXIT; (* Zahl2 > Zahl1 *)π FOR i := 1 TO zahl1.stellen DO (* alle Stellen abarbeiten *)π BEGINπ IF (zahl1.zahl[i] >= (zahl2.zahl[i] + uebertrag)) THENπ (* Zahl1[i] >= Zahl2[i] mit Berücksichtigung des Übertrags *)π BEGINπ ergebnis.zahl[i] := zahl1.zahl[i] - (zahl2.zahl[i] + uebertrag);π (* Differenz der Zahlen ermitteln *)π uebertrag := 0; (* kein Übertrag *)π ENDπ ELSEπ BEGINπ ergebnis.zahl[i] := LongInt(zahl1.zahl[i] + 65536) - (zahl2.zahl[i] +πuebertrag);π uebertrag := 1;π END;π END;π ergebnis.stellen := zahl1.stellen;π (* Annahme: gleich viel Stellen wie Zahl1 *)π WHILE (ergebnis.zahl[ergebnis.stellen] = 0) AND (ergebnis.stellen > 0) DOπ DEC(ergebnis.stellen); (* richtige Stellenzahl ermitteln *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* Mul2CalcStr multipliziert einen CalcString mit 2 *)ππPROCEDURE Mul2CalcStr(VAR calcZahl : CalcStr);πVAR i : WORD; (* Zählvariable *)πBEGINπ WITH calcZahl DO (* Record als Grundlage *)π IF ((stellen = 1) AND (zahl[1] = 0)) OR (stellen = 0) THENπ ELSE (* CalcZahl ist 0 => Ergebnis ist 0 *)π BEGIN (* Sonst ist Ergebnis <> 0 *)π IF (zahl[stellen] AND 32768) > 0 THENπ BEGIN (* Ist 16.Bit der letzten Stelle gesetzt ? *)π INC(stellen); (* Stellenzahl um 1 erhöhen *)π zahl[stellen] := 0; (* und mit 0 initialisieren *)π END;π FOR i := (stellen - 1) DOWNTO 1 DO (* Zahl abarbeiten *)π BEGINπ zahl[i + 1] := zahl[i + 1] SHL 1; (* Zahl[i + 1] * 2 *)π IF (zahl[i] AND 32768) > 0 THEN INC(zahl[i + 1]);π END; (* Bei Überlauf bei Zahl[i] => Zahl[i + 1] erhöhen *)π zahl[1] := zahl[1] SHL 1; (* 1. Zahl mit 2 multiplizieren *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* Div2CalcStr dividiert einen CalcString durch 2 *)ππPROCEDURE Div2CalcStr(VAR calcZahl : CalcStr);πVAR i : WORD; (* Zählvariable *)πBEGINπ WITH calcZahl DOπ IF ((stellen = 1) AND (zahl[1] = 0)) OR (stellen = 0) THENπ ELSE (* calcZahl = 0 => calcZahl * 2 = 0 *)π BEGINπ FOR i := 1 TO (stellen - 1) DO (* Zahl abarbeiten *)π BEGINπ zahl[i] := zahl[i] SHR 1; (* Zahl[i] DIV 2 *)π IF (zahl[i + 1] AND 1) > 0 THENπ (* Falls bei Zahl[i + 1] ein Unterlauf auftritt *)π zahl[i] := zahl[i] OR 32768; (* Bit 16 bei Zahl[i] setzen *)π END;π zahl[stellen] := zahl[stellen] SHR 1; (* letzte Stelle DIV 2 *)π IF (zahl[stellen] = 0) THEN DEC(stellen);π (* Falls letzte Stelle 0 ist => Stellen um 1 erniedrigen *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* MulCalcStr multiplizier2 zahl1 mit zahl2 *)ππPROCEDURE MulCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr);πVAR hilfe : CalcStr; (* HilfsCalcString *)π hilfe1 : CalcStr; (* HilfsCalcString *)π hilfe2 : CalcStr; (* HilfsCalcString *)π i, j : WORD; (* Zählvariablen *)π wert : WORD; (* Wert von Zahl an der i.ten Stelle *)πBEGINπ IF LessCalcStr(zahl1, zahl2) THEN (* Falls zahl1 < zahl2 *)π BEGINπ hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *)π hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *)π ENDπ ELSEπ BEGINπ hilfe2 := zahl1; (* Hilfe2 wird Zahl1 zugewiesen *)π hilfe1 := zahl2; (* Hilfe1 wird Zahl2 zugewiesen *)π END;π ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π IF ((hilfe1.stellen = 1) AND (hilfe1.zahl[1] = 0)) OR (hilfe1.stellen = 0)πTHENπ ELSE (* Ergebnis=0, weil X * 0 = 0 *)π BEGINπ i := 1; (* i mit 1 initialisieren *)π WHILE (i <= (hilfe1.stellen - 1)) DO (* Hilfe 1 abarbeiten *)π BEGINπ wert := hilfe1.zahl[i]; (* Wert = i.Zahl *)π j := 1; (* j mit 1 initialisieren *)π WHILE (j <= 16) DO (* alle Bits abarbeiten *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls 1.Bit gesetzt *)π BEGINπ AddCalcStr(ergebnis, hilfe2, hilfe);π (* Ergebnis und Hilfe2 addieren *)π ergebnis := hilfe; (* Ergebnis aus Addition *)π END;π wert := wert SHR 1; (* Wert DIV 2 *)π Mul2CalcStr(hilfe2); (* Hilfe2 * 2 *)π INC(j); (* j um 1 erhöhen *)π END;π INC(i); (* i um 1 erhöhen *)π END;π wert := hilfe1.zahl[hilfe1.stellen]; (* letzte Stelle behandeln *)π WHILE wert > 0 DO (* Solange noch 1 Bit gesetzt ist *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls Bit 1 gesetzt ist *)π BEGINπ AddCalcStr(ergebnis, hilfe2, hilfe);π (* Ergebnis und Hilfe2 addieren *)π ergebnis := hilfe; (* Ergebnis aus Addition *)π END;π wert := wert SHR 1; (* Wert DIV 2 *)π Mul2CalcStr(hilfe2); (* Hilfe2 * 2 *)π END;π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* DivCalcStr dividiert einen CalcString durch einen anderen *)ππFUNCTION DivCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) :πBOOLEAN;πVAR hilfe : CalcStr; (* HilfsCalcString *)ππ hilfe1 : CalcStr; (* HilfsCalcString *)π hilfe2 : CalcStr; (* HilfsCalcString *)π EINS : CalcStr; (* konstanter HilfsString für 1 *)πBEGINπ IF ((zahl2.stellen = 1) AND (zahl2.zahl[1] = 0)) OR (zahl2.stellen = 0) THENπ DivCalcStr := FALSE (* Division durch 0 nicht möglich *)π ELSEπ BEGINπ EINS := EMPTYCALCSTR; (* Eins initialisieren *)π EINS.stellen := 1; (* Eins besitzt 1 Stelle *)π EINS.zahl[1] := 1; (* diese wird mit 1 belegt *)π ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *)π hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *)π WHILE NOT (GreaterCalcStr(hilfe2, hilfe1)) DOπ Mul2CalcStr(hilfe2);π (* schiebe hilfe2 solange nach links, bis dividiert werden kann *)π WHILE NOT (EqualCalcStr(hilfe2, zahl2)) DO (* Abbruchbedingung *)π BEGINπ Mul2CalcStr(ergebnis); (* Ergebnis mit 2 multiplizieren *)π Div2CalcStr(hilfe2); (* Hilfe2 durch 2 dividieren *)π IF NOT (GreaterCalcStr(hilfe2, hilfe1)) THENπ (* falls hilfe2 nicht > hilfe1 *)π BEGINπ SubCalcStr(hilfe1, hilfe2, hilfe); (* Hilfe1 - Hilfe2 *)π hilfe1 := hilfe; (* Hilfe1 wird Hilfe zugewiesen *)π AddCalcStr(ergebnis, EINS, hilfe);(* zum Ergebnis 1 addieren *)π ergebnis := hilfe; (* Ergebnis wird hilfe zugewiesen *)π END;π END;π DivCalcStr := TRUE; (* Division erfolgreich *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* ModCalcStr berechnet den Rest bei Division von Zahl1 durch Zahl2 *)ππFUNCTION ModCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) :πBOOLEAN;πVAR hilfe : CalcStr; (* HilfsCalcString *)π hilfe1 : CalcStr; (* HilfsCalcString *)π hilfe2 : CalcStr; (* HilfsCalcString *)π EINS : CalcStr; (* konstanter HilfsString für 1 *)πBEGINπ IF ((zahl2.stellen = 1) AND (zahl2.zahl[1] = 0)) OR (zahl2.stellen = 0) THENπ ModCalcStr := FALSE (* Division durch 0 nicht möglich *)π ELSEπ BEGINπ EINS := EMPTYCALCSTR; (* Eins initialisieren *)π EINS.stellen := 1; (* Eins besitzt 1 Stelle *)π EINS.zahl[1] := 1; (* diese wird mit 1 belegt *)π ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π IF GreaterCalcStr(zahl2, zahl1) THEN (* falls Zahl2 > Zahl1 *)π ergebnis := zahl1 (* Ergebnis ist Zahl1 *)π ELSEπ BEGINπ hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *)π hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *)π WHILE NOT (GreaterCalcStr(hilfe2, hilfe1)) DOπ Mul2CalcStr(hilfe2);π (* schiebe hilfe2 solange nach links, bis dividiert werden kann *)π WHILE NOT (EqualCalcStr(hilfe2, zahl2)) DO (* Abbruchbedingung *)π BEGINπ Mul2CalcStr(ergebnis); (* Ergebnis mit 2 multiplizieren *)π Div2CalcStr(hilfe2); (* Hilfe2 durch 2 dividieren *)π IF NOT (GreaterCalcStr(hilfe2, hilfe1)) THENπ (* falls hilfe2 nicht > hilfe1 *)π BEGINπ SubCalcStr(hilfe1, hilfe2, hilfe); (* Hilfe1 - Hilfe2 *)π hilfe1 := hilfe; (* Hilfe1 wird Hilfe zugewiesen *)π AddCalcStr(ergebnis, EINS, hilfe);π (* zum Ergebnis 1 addieren *)π ergebnis := hilfe; (* Ergebnis wird hilfe zugewiesen *)π END;π END;π ModCalcStr := TRUE; (* Division erfolgreich *)π END;π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* ExptCalcStr berechnet Basis^Exponent *)ππPROCEDURE ExptCalcStr(VAR basis, exponent: CalcStr; VAR ergebnis : CalcStr);πVAR hilfe : CalcStr; (* HilfsCalcString *)π hilfe1 : CalcStr; (* HilfsCalcString *)π i, j : WORD; (* Zählvariablen *)π wert : WORD; (* Wert des Exponenten an der i.ten Stelle *)πBEGINπ ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π ergebnis.stellen := 1; (* Ergebnis hat min. 1 Stelle *)π ergebnis.zahl[1] := 1; (* Ergebnis >= 1 *)π IF ((exponent.stellen = 1) AND (exponent.zahl[1] = 0)) OR (exponent.stellen =π0) THENπ ELSE (* Exponent = 0 => Ergebnis = 1 *)π BEGINπ hilfe1 := basis; (* Hilfe1 wird Basis zugewiesen *)π i := 1; (* i wird mit 1 initialisiert *)π WHILE (i <= (exponent.stellen - 1)) DO (* Exponenten abarbeiten *)π BEGINπ wert := exponent.zahl[i]; (* i.te Stelle des Exponenten *)π INC(i); (* i um 1 erhöhen *)π j := 1; (* j wird mit 1 initialisiert *)π WHILE (j <= 16) DO (* alle Bits abarbeiten *)π BEGINπ IF (wert AND 1) = 1 THEN (* falls 1. Bit gesetzt ist *)π MulCalcStr(ergebnis, hilfe1, ergebnis);π (* Ergebnis mit Hilfe1 multiplizieren *)π MulCalcStr(hilfe1, hilfe1, hilfe1); (* Hilfe1 quadrieren *)π wert := wert SHR 1; (* Wert DIV 2 *)π INC(j); (* 1 Bit weitergehen *)π END;π END;π wert := exponent.zahl[exponent.stellen]; (* letzte Stelle behandeln *)π WHILE (wert <> 0) DO (* solange noch 1 Bit gesetzt *)π BEGINπ IF (wert AND 1) = 1 THEN (* falls 1. Bit gesetzt ist *)π MulCalcStr(ergebnis, hilfe1, ergebnis);π (* Ergebnis mit Hilfe1 multiplizieren *)π MulCalcStr(hilfe1, hilfe1, hilfe1); (* Hilfe1 quadrieren *)π wert := wert SHR 1; (* Wert DIV 2 *)π END;π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* RandomCalcStr liefert eine Zufallszahl < calcZahl *)ππPROCEDURE RandomCalcStr(VAR calcZahl: CalcStr; VAR ergebnis : CalcStr);πVAR i : WORD; (* Zählvariable *)πBEGINπ ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π ergebnis.stellen := calcZahl.stellen; (* Annahme: Stellenzahl ist gleich *)π FOR i := 1 TO (calcZahl.stellen - 1) DOπ ergebnis.zahl[i] := Random(65535); (* zufällige Zahl < 65535 *)π ergebnis.zahl[ergebnis.stellen] := Random(calcZahl.zahl[calcZahl.stellen]);π (* letzte Zahl muß kleiner Ausgangszahl sein *)π WHILE (ergebnis.zahl[ergebnis.stellen] = 0) AND (ergebnis.stellen > 1) DOπ DEC(ergebnis.stellen); (* führende Nullen abschneiden *)π IF ((ergebnis.stellen = 1) AND (ergebnis.zahl[1] = 0)) OR (ergebnis.stellen =π0) THENπ BEGIN (* Ergebnis darf nicht 0 sein *)π ergebnis.stellen := 1; (* min. 1 Stelle *)π ergebnis.zahl[1] := 1; (* diese mit 1 besetzen *)π END;πEND;ππ(* ----------------------------------------------------------------------- *)π(* MulModCalcStr multipliziert ein Zahl modulo modul *)ππPROCEDURE MulModCalcStr(VAR zahl1, zahl2, modul : CalcStr; VAR ergebnis :πCalcStr);πVAR i, j : WORD; (* Zählvariablen *)π wert : WORD; (* Wert von Zahl an i.ter Stelle *)π hilfe : CalcStr; (* HilfsCalcString *)π hilfe1 : CalcStr; (* HilfsCalcString *)π hilfe2 : CalcStr; (* HilfsCalcString *)πBEGINπ IF LessCalcStr(zahl1, zahl2) THEN (* Falls Zahl1 < Zahl2 *)π BEGINπ ModCalcStr(zahl1, modul, hilfe1); (* Divisionsrest Zahl1/Modul *)π ModCalcStr(zahl2, modul, hilfe2); (* Divisionsrest Zahl2/Modul *)π ENDπ ELSEπ BEGINπ ModCalcStr(zahl1, modul, hilfe2); (* Divisionsrest Zahl1/Modul *)π ModCalcStr(zahl2, modul, hilfe1); (* Divisionsrest Zahl2/Modul *)π END;π ergebnis := EMPTYCALCSTR; (* ErgebnisCalcString initialisieren *)π IF ((hilfe1.stellen = 1) AND (hilfe1.zahl[1] = 0)) OR (hilfe1.stellen = 0)πTHENπ (* Hilfe1 muß ungleich 0 sein *)π ELSEπ BEGINπ i := 1; (* i mit 1 initialisieren *)π WHILE (i <= (hilfe1.stellen - 1)) DOπ (* alle Stellen von Hilfe1 abarbeiten *)π BEGINπ wert := hilfe1.zahl[i]; (* aktuellen Wert ermitteln *)π j := 1; (* j mit 1 initialisieren *)π WHILE (j <= 16) DO (* alle Bits abarbeiten *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls Bit 1 gesetzt ist *)π BEGINπ AddCalcStr(ergebnis, hilfe2, hilfe);π (* Hilfe2 zum Ergebnis addieren *)π ergebnis := hilfe; (* und dem Ergebnis zuweisen *)π END;π wert := wert SHR 1; (* Wert durch 2 dividieren *)π Mul2CalcStr(hilfe2); (* Hilfe2 mit 2 multiplizieren *)π INC(j); (* j um 1 erhöhen *)π END;π INC(i); (* i um 1 erhöhen *)π END;π wert := hilfe1.zahl[hilfe1.stellen];π (* letzte Zahl gesondert behandeln *)π WHILE (wert > 0) DO (* solange noch ein Bit gesetzt *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls 1. Bit gesetzt ist *)π BEGINπ AddCalcStr(ergebnis, hilfe2, hilfe);π (* Hilfe2 zum Ergebnis addieren *)π ergebnis := hilfe; (* und dem Ergebnis zuweisen *)π END;π wert := wert SHR 1; (* Wert durch 2 dividieren *)π Mul2CalcStr(hilfe2); (* Hilfe2 mit 2 multiplizieren *)π END;π END;π hilfe1 := ergebnis; (* Hilfe1 wird Ergebnis zugewiesen *)π ModCalcStr(hilfe1, modul, ergebnis); (* Divisionsrest hilfe1/Modul *)πEND;ππ(* ----------------------------------------------------------------------- *)π(* ExptModCalcStr berechnet basis^exponent MOD modul *)ππPROCEDURE ExptModCalcStr(VAR basis, exponent, modul : CalcStr; VAR ergebnis :πCalcStr);πVAR i, j : WORD; (* Zählvariablen *)π wert : WORD; (* Wert von Zahl an i.ter Stelle *)π hilfe : CalcStr; (* HilfsCalcString *)π hilfe1 : CalcStr; (* HilfsCalcString *)πBEGINπ ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *)π ergebnis.stellen := 1; (* Ergebnis besitzt min. 1 Stelle *)π ergebnis.zahl[1] := 1; (* Ergebnis hat mind. Wert 1 *)π IF ((exponent.stellen = 1) AND (exponent.zahl[1] = 0)) OR (exponent.stellen =π0) THENπ (* Exponent = 0 => Ergebnis = 1*)π ELSEπ BEGINπ ModCalcStr(basis, modul, hilfe1); (* Divisionsrest Basis/Modul *)π i := 1; (* i mit 1 initialisieren *)π WHILE (i <= (exponent.stellen - 1)) DOπ BEGINπ wert := exponent.zahl[i]; (* Wert = i.te Stelle von Exponent *)π j := 1; (* j mit 1 initialisieren *)π WHILE (j <= 16) DO (* alle Bits abarbeiten *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls Bit 1 gesetzt ist *)π BEGINπ MulModCalcStr(ergebnis, hilfe1, modul, hilfe);π (* Ergebnis * Hilfe1 MOD Modul *)π ergebnis := hilfe; (* und dem Ergebnis zuweisen *)π END;π wert := wert SHR 1; (* Wert durch 2 dividieren *)π MulModCalcStr(hilfe1, hilfe1, modul, hilfe);π (* Hilfe1*Hilfe1 MOD Modul *)π hilfe1 := hilfe; (* und wieder Hilfe1 zuweisen *)π INC(j); (* j um 1 erhöhen *)π END;π INC(i); (* 1 um 1 erhöhen *)π END;π wert := exponent.zahl[exponent.stellen];π (* letzte Zahl gesondert behandeln *)π WHILE (wert > 0) DO (* solange noch ein Bit gesetzt *)π BEGINπ IF (wert AND 1) > 0 THEN (* Falls 1. Bit gesetzt ist *)π BEGINπ MulModCalcStr(ergebnis, hilfe1, modul, hilfe);π (* Hilfe1*Ergebnis MOD Modul *)π ergebnis := hilfe; (* und dem Ergebnis zuweisen *)π END;π wert := wert SHR 1; (* Wert durch 2 dividieren *)π MulModCalcStr(hilfe1, hilfe1, modul, hilfe);π (* Hilfe1*Hilfe1 MOD Modul *)π hilfe1 := hilfe; (* und wieder hilfe1 zuweisen *)π END;π END;πEND;ππ(* ----------------------------------------------------------------------- *)ππBEGINππ Randomize; (* Zufallsgenerator einschalten *)ππ (* Initialiseren eines globalen Leerstrings *)π WITH EMPTYCALCSTR DO (* Recordtyp abarbeiten *)π BEGINπ stellen := 0; (* Länge ist 0 *)π FOR i := 1 TO MAXCALCSTR DO zahl[i] := 0; (* zahl initialisieren *)π END;π (* Ende der Initialisierung *)ππEND.π 9 08-25-9409:11ALL RUSS COX Sierpinski's Gasket... SWAG9408 up╙u 24 ₧ {π Sierpinski's Gasket using Pascal's Triangle.π Written by Russ Cox. June 10, 1994.ππ Sierpinski's Gasket starts with an equilateral triangle. /\π / X \π /-------\ππ This triangle then copies itself and puts a copy to the right andπ at the tip.ππ /\π / X \π /\------/\π / X \ /X \π /-------\/-------\ππ It keeps repeating this forever and you get this cool shape, just a lotπ bigger. This was one of the first fractals.ππ Blaise Pascal invented what is known as Pascal's Triangle.ππ 1π 1 1π 1 2 1π 1 3 3 1π 1 4 6 4 1π etc.π You start with sides of 1. As you go down the triangle, to obtain aπ value, you add the numbers above to the left and above to the right.ππ It just so happens that if you color the pixel for Pascal's Triangleπ as to whether or not the number is odd or even, you get Sierpinski'sπ Gasket on your screen. Have fun!!!ππ (Feel free to include this in SWAG if you feel like it. I would put itπ in MATH. )ππ ■ Done! - Kerry ■πππ P.S. If you mess with the right value and leave mid alone... (i.e. makeπ right 480 or something, the part that would have been cut off isπ instead folded over on top of the triangle.ππ}ππprogram gasket;πuses graph;πvarπ grDriver : Integer;π grMode : Integer;π ErrCode : Integer;πconstπ right = 640;π mid = 320;π bottom = 256;ππvarπ oddeven : array[1..right] of Boolean;π c, d, e : integer;π prevoe : array[1..right] of Boolean;ππbeginπgrDriver := Detect;π InitGraph(grDriver,grMode,'e:\bp\bgi');π ErrCode := GraphResult;π if ErrCode <> grOk thenπ beginπ WriteLn('Graphics error:',π GraphErrorMsg(ErrCode));π halt(1);π end;ππ for c := 1 to right doπ prevoe[ c ] := FALSE;ππ prevoe[ mid ] := TRUE;ππ putpixel( mid, 1 , WHITE );π for c := 2 to bottom doπ beginπ for d := 1 to right doπ beginπ if d = 1 thenπ oddeven[ d ] := prevoe[ d + 1 ]π else if d = right thenπoddeven[ d ] := prevoe[ d - 1 ]π elseπ oddeven[ d ] := prevoe[ d - 1 ] xor prevoe[ d + 1 ];ππ if ( d < 640 ) AND ( c < 480 ) thenπ if oddeven[ d ] = TRUE thenπ putpixel( d, c, WHITE )π elseπ putpixel( d, c, BLACK );ππ end;π move( oddeven, prevoe, right );π end;πππend.ππ{πIf you use as a value any power of 2 in the previous program, you get aπfull triangle, without bits and pieces falling off.π} 10 08-25-9409:12ALL JAMIE MORTIMER Virtual Coords SWAG9408 ∩`dM 19 ₧ {πYou can do a basic horizontal starfeild where all you need is an array ofπx,y locations, a routine to draw the stars in the next position, a routineπto remove the old stars, and a routine to update the position array. Or oneπroutine to do all that. That gets boring once you write one. So you want oneπyou can fly into. Now you need x,y and a z coord. To get the virtual x,yπscreen coords for each point, take their 3d-x coord and divide by the 3d-zπcoord, and do the same for the y. This will give you a real number, andπreals are slow so here's an example of just that math using only integers.π}π X : Integer; {3d x coord -maxint to maxint, left to right}π Y : Integer; {y " " top to bottom}π Z : Integer; {z -1..-1023 where '-' is into screen}π xx : integer; {2d x coord}π yy : integer; {y}ππxx:=vidwidth div 2 + longint(x)*1024 div z;πyy:=vidheight div 2 + longint(y)*1024 div z;π{πThat'll give you just plain depth scaling for one star. For many stars,πjust keep an array like this for each of those:π}π X : array [1..maxstars] of integer;π{πYou'd basically follow this pattern:π}π for t:=1 to maxstars doπ beginπ {if star is visible, clear it}π if getpixel(xx[t],yy[t])=starcolor thenπ putpixel(xx[t],yy[t],backgroundcolor);π {update star position}π whatever math you want. Maybe just:π inc(z[t]);π if z<=0 thenπ beginπ x:=random(2048)-1024;π y:=random(2048)-1024;π z:=-1024;π end;π {translate 3d to 2d}π xx[tt]:= {etc from above}π {draw new points}π if getpixel(xx[t],yy[t])=backgroundcolor thenπ putpixel(xx[t],yy[t],starcolor);π end;π{πof course this won't compile, but I assume you like to code and so I'mπonly giving you a general idea. Then you can put another variable in, aπfor example, which is not an array but just a constant which indicatedπthe "angle" of rotation around the z axis. (spinning) it's easy toπimplement that into the equation without any 3d math stuff.π}πxx[tt]:=longint(x[t])*1024 div z[t] * sintable[a mod 360]π div (sin table precision constant, usually 256);ππyy[tt]:=longint(y[t])*1024 div z[t] * costable[a mod 360]π div 256;π